UserControl внутри FlipView
Резюме: я не могу получить UserControl, который находится внутри FlipView, чтобы обновлять / обновлять себя при смене страниц в FlipView. UserControl зависит от своего кода для выполнения необходимых вычислений для собственного дисплея.
Введение: я создал графический элемент UserControl в Windows 8 из-за отсутствия такого элемента управления в настоящее время (за исключением некоторых сторонних производителей). XAML для элемента управления создает оси и объявляет путь, используемый для фактического рисования линии графа, а выделенный фрагмент кода создает класс, который генерирует точки заговора для этого пути. Создание экземпляра этого класса пути к графу выполняется загруженным обработчиком событий в коде после того, как оси были правильно отрисованы, чтобы получить размер области построения. Параметры конструктора включают в себя различные данные, специфичные для точек заговора, а также ссылки на дочерние элементы управления, которые используются для масштабирования.
Вот контроль:
<Grid>
<Border Background="LightGray"
Margin="0,10">
<Grid Name="MainGrid">
<Grid.RowDefinitions>
<RowDefinition Height="1*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="2*"/>
<RowDefinition Height="2*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="2*"/>
<ColumnDefinition Width="40*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Border Grid.Row="1"
Grid.Column="0"
Grid.RowSpan="11"
Name="yAxisBorder">
<!--this canvas is written to in DrawGraph.cs -->
<Canvas Name="yAxis">
</Canvas>
</Border>
<Border Grid.Row="11"
Grid.Column="1"
Name="xAxisBorder"
BorderBrush="Black">
<!--this canvas is written to in DrawGraph.cs -->
<Canvas Name="xAxis"/>
</Border>
<Border x:Name ="GraphAxis"
Grid.Row="1"
Grid.Column="1"
Grid.RowSpan="10"
BorderThickness="2,2,2,2"
BorderBrush="Black"
Loaded="GraphAxis_Loaded">
<Border.Background>
<LinearGradientBrush EndPoint="0.5,1"
StartPoint="0.5,0">
<GradientStop Color="Black"/>
<GradientStop x:Name="GraphStop2"
Offset="0.554" Color="White"/>
</LinearGradientBrush>
</Border.Background>
<!--this path is written to in DrawGraph.cs -->
<Path x:Name="GraphLine"
StrokeThickness="2"
Data="M0,0">
<Path.Stroke>
<SolidColorBrush Color="Black"/>
</Path.Stroke>
<Path.Fill>
<LinearGradientBrush EndPoint="0.5,1" StartPoint="0.5,0">
<GradientStop Color="Black"/>
<GradientStop Color="LightPink"
Offset="1"/>
</LinearGradientBrush>
</Path.Fill>
</Path>
</Border>
<!--These borders draw the grid-lines on the graph-->
<Border Grid.Row="1"
Grid.Column="1"
BorderThickness="0,0,0,0.5"
BorderBrush="Black"/>
<Border Grid.Row="2"
Grid.Column="1"
BorderThickness="0,0,0,0.5"
BorderBrush="Black">
</Border>
<Border Grid.Row="3"
Grid.Column="1"
BorderThickness="0,0,0,0.5"
BorderBrush="Black">
</Border>
<Border Grid.Row="4"
Grid.Column="1"
BorderThickness="0,0,0,0.5"
BorderBrush="Black">
</Border>
<!--This border is for drawing the x-axis for -ve inflation-->
<Border Grid.Row="5"
Grid.Column="1"
x:Name="xAxisLine1"
BorderThickness="0,0,0,0.5"
BorderBrush="Black">
</Border>
<Border Grid.Row="6"
Grid.Column="1"
BorderThickness="0,0,0,0.5"
BorderBrush="Black">
</Border>
<Border Grid.Row="7"
Grid.Column="1"
BorderThickness="0,0,0,0.5"
BorderBrush="Black">
</Border>
<Border Grid.Row="8"
Grid.Column="1"
BorderThickness="0,0,0,0.5"
BorderBrush="Black">
</Border>
<Border Grid.Row="9"
Grid.Column="1"
BorderThickness="0,0,0,0.5"
BorderBrush="Black">
</Border>
<Border x:Name="xAxisLine2"
Grid.Row="10"
Grid.Column="1"
BorderThickness="0,0,0,2"
BorderBrush="Black">
</Border>
</Grid>
</Border>
</Grid>
Вот фрагмент кода с созданием объекта, который рисует линию графика (путь называется GraphLine в XAML:
public void GraphAxis_Loaded(object sender, RoutedEventArgs e)
{
ApplicationDataContainer appData = ApplicationData.Current.RoamingSettings;
Country selectedCountry = CountryDataSource.GetCountry((int)appData.Values["Country"]);
string month1 = selectedCountry.FirstMonth, month2 = selectedCountry.LastMonth;
int year1 = selectedCountry.FirstYear, year2 = selectedCountry.LastYear;
DrawGraph dGraph = new DrawGraph(selectedCountry, month1, year1, month2, year2,
GraphAxis.ActualHeight, GraphAxis.ActualWidth, GraphLine, xAxis, xAxisBorder, yAxis, MainGrid, xAxisLine1, xAxisLine2);
}
}
... и, наконец, класс DrawGraph:
public class DrawGraph
{
List<String> months = new List<string> { "JAN", "FEB", "MAR", "APR", "MAY", "JUN", "JUL", "AUG", "SEP", "OCT", "NOV", "DEC" };
public DrawGraph(Country currentC, string nearMonth, int nearYear, string farMonth, int farYear, double cHeight, double cWidth, Path pGraphLine, Canvas xAxis, Border xAxisBorder, Canvas yAxis, Grid GraphGrid, Border xAxisLine1, Border xAxisLine2)
{
int periods = 0, years = farYear - nearYear, firstDateIndex = 0, lastDateIndex = 0, n = 0, prIndex = 0, yScalePve = 0, yScaleNve = 0, yScaleExtent = 0;
double endDateIndex, minFactor = 1000, maxFactor = 0, inflationFactor,
baseFactor = 0, yOffSet = 0;
plotPoint[] plotResults;
cHeight -= 4; // this is for the 4 pixels taken up by the border
// count up the months between the start and end points
foreach (KeyValuePair<string, double> rpiRecord in currentC.RpiData)
{
if (rpiRecord.Key == nearMonth + nearYear.ToString())
{
firstDateIndex = n;
}
if (rpiRecord.Key == farMonth + farYear.ToString())
{
lastDateIndex = n;
}
n++;
}
// calculate the number of points to plot
periods = lastDateIndex - firstDateIndex + 1;
// put together the array of dates (relative) and factors to plot
if (periods > 1)
{
plotResults = new plotPoint[periods];
n = 0;
foreach (KeyValuePair<string, double> rpiRecord in currentC.RpiData)
{
if (n >= firstDateIndex & n <= lastDateIndex)
{
if (n == firstDateIndex)
{
baseFactor = rpiRecord.Value;
plotResults[prIndex] = new plotPoint(prIndex, 0);
minFactor = 0;
maxFactor = 0;
}
else
{
// get the inflation factor and date position and populate the plotPoints array
inflationFactor = (rpiRecord.Value - baseFactor) / baseFactor * 100;
plotResults[prIndex] = new plotPoint(prIndex, inflationFactor);
// these are used for the height scaling
if (inflationFactor > maxFactor)
{
maxFactor = inflationFactor;
}
if (inflationFactor < minFactor & rpiRecord.Value != 0)
{
minFactor = inflationFactor;
}
}
prIndex++;
}
n++;
}
// now decide on the y-axis scale
// firstly, is the maximum in the units, tens, hundreds or thousands
if (maxFactor - 1 < 0)
{
yScalePve = 1;
}
else if (maxFactor - 2 < 0)
{
yScalePve = 2;
}
else if (maxFactor - 5 < 0)
{
yScalePve = 5;
}
else if (maxFactor - 10 < 0)
{
yScalePve = 10;
}
else if (maxFactor - 50 < 0)
{
yScalePve = 50;
}
else if (maxFactor - 100 < 0)
{
yScalePve = 100;
}
else if (maxFactor - 500 < 0)
{
yScalePve = 500;
}
else if (maxFactor - 1000 < 0)
{
yScalePve = 1000;
}
else if (maxFactor - 5000 < 0)
{
yScalePve = 5000;
}
else
{
yScalePve = 10000;
}
if (minFactor < 0)
{
if (minFactor + 1 > 0)
{
yScaleNve = 1;
}
else if (minFactor + 2 > 0)
{
yScaleNve = 2;
}
else if (minFactor + 5 > 0)
{
yScaleNve = 5;
}
else if (minFactor + 10 > 0)
{
yScaleNve = 10;
}
else if (minFactor + 50 > 0)
{
yScaleNve = 50;
}
else if (minFactor + 100 > 0)
{
yScaleNve = 100;
}
else if (minFactor + 500 > 0)
{
yScaleNve = 500;
}
else if (minFactor + 1000 > 0)
{
yScaleNve = 1000;
}
else if (minFactor + 5000 > 0)
{
yScaleNve = 5000;
}
else
{
yScaleNve = 10000;
}
// calculate the position of the xAxis on the yScale
if (maxFactor <= minFactor * -100) // this is to prevent small -ves moving the x-axis to the middle
{
yOffSet = cHeight / 2;
}
}
// calculate the position of the xAxis on the yScale
yScaleExtent = yScalePve + yScaleNve;
if (cHeight > 0) // this prevents the borders being re-sized before the grids have been rendered
{
// this re-sizes the rows in the grid displaying the graph - there is a border in the 5th row (defined in the XAML)
// which acts as the x axis and this adjusts the line thickness to where the x axis should be
if (yOffSet == 0)
{
// this draws the x-axis when it is at the bottom position
xAxisLine1.BorderThickness = new Thickness(0, 0, 0, 1);
xAxisLine2.BorderThickness = new Thickness(0, 0, 0, 2);
cHeight += 1; // this is for the extra pixel taken up by the border
}
else
{
// this draws the x-axis when it is at the middle position
xAxisLine1.BorderThickness = new Thickness(0, 0, 0, 2);
xAxisLine2.BorderThickness = new Thickness(0, 0, 0, 1);
cHeight -= 1; // this is for the extra pixel taken up by the border
}
}
// this is used for the width scaling
endDateIndex = plotResults[plotResults.Length - 1].plotDate;
// zero-base the plot results
plotResults[0].plotDate = 0;
plotResults[0].plotFactor = 0 + yOffSet;
PathFigure myPathFigure = new PathFigure();
myPathFigure.StartPoint = new Point(0, cHeight - yOffSet);
PathSegmentCollection myPathSegmentCollection = new PathSegmentCollection();
for (int x = 1; x < plotResults.Length; x++)
{
// re-base the array dates with respect to the plot area width
plotResults[x].plotDate *= cWidth / endDateIndex;
// re-base the array factors with respect to the y-axis
plotResults[x].plotFactor = plotResults[x].plotFactor / yScaleExtent;
// then re-base the array into the units of the plot area
plotResults[x].plotFactor = plotResults[x].plotFactor * (cHeight - yOffSet);
// generate the LineSegment objects for each plotPoint
LineSegment myLineSegment = new LineSegment();
myLineSegment.Point = new Point(plotResults[x].plotDate, (cHeight - yOffSet) - plotResults[x].plotFactor);
myPathSegmentCollection.Add(myLineSegment);
}
// these 2 additional line segments create an enclosed polygon for the fill to go into
LineSegment myLineSegment1 = new LineSegment();
// this line draws down vertically on the right-hand y axis
myLineSegment1.Point = new Point(cWidth, cHeight - yOffSet); //
myPathSegmentCollection.Add(myLineSegment1);
LineSegment myLineSegment2 = new LineSegment();
// this line draws across to the left on the x axis
myLineSegment2.Point = new Point(0, cHeight - yOffSet);
myPathSegmentCollection.Add(myLineSegment2);
// this sets up the LineSegments for the PathFigure, the
// PathFigure for the PathGeometry and the PathGeometry for the PathData!!
myPathFigure.Segments = myPathSegmentCollection;
PathFigureCollection myPathFigureCollection = new PathFigureCollection();
myPathFigureCollection.Add(myPathFigure);
PathGeometry myPathGeometry = new PathGeometry();
myPathGeometry.Figures = myPathFigureCollection;
pGraphLine.Data = myPathGeometry;
Calculate_xAxis(nearYear, farYear, nearMonth, farMonth, xAxis, xAxisBorder);
Calculate_yAxis(yScalePve, yScaleNve, xAxis, yAxis, yOffSet);
}
}
Проблема: я хочу отобразить этот графический элемент управления в FlipView, который связан с наблюдаемой коллекцией, которая содержит наборы данных, используемые как FlipView, так и классом рисования пути. Как видно из кода, в самом элементе управления Graph нет привязки данных. Данные получены из ApplicationData и размеров элементов управления в самом UserControl. Это все работает нормально, когда FlipView запускается, но когда я переворачиваю страницы, графики не обновляются.
Я посмотрел на эту проблему с нескольких точек зрения:
Во-первых, похоже, что при перелистывании страниц в FlipView загруженное событие не перезапускается для элемента управления осью (Граница) в UserControl внутри FlipView, но оно запускается в первый раз. Я не могу найти какое-либо другое событие для подключения, кроме загруженного события.
Во-вторых, можно ли заставить весь граф работать без привязки данных? Я понимаю, что для этого мне нужно было бы создать свойства зависимости в UserControl, но даже тогда мне все равно нужно было бы создать экземпляр DrawGraph в коде позади.
Может кто-нибудь здесь увидеть, есть ли решение этой проблемы? Или я подхожу к этому неправильно? Должен ли я поместить всю функциональность DrawGraph в процедуру где-то еще, которая предварительно заполняет Наблюдаемую коллекцию всеми точками заговора, а затем привязывает график UserControl к этому?
Любые предложения приветствуются. Я довольно новичок в этом, и это моя первая публикация здесь, и я надеюсь, что кто-то может научить меня моему подходу. Спасибо