Why aren't my line showing up on my ItemsControl? - c#

I'm attaching an ObservableCollection to it filled with a class I created. The ObservableCollection begins empty but is filled once the file is loaded. I've checked and it's properly loading the CanvasStart and CanvasEnd values. As far as I was aware the ItemsControl should be updating itself when the points are added to the ObservableCollection. See below:
my CanvasLine class:
public class CanvasLine
{
public Point DxfStart { get; set; }
public Point DxfEnd { get; set; }
public Point CanvasStart { get; set; }
public Point CanvasEnd { get; set; }
public string Layer { get; set; }
public List<double> Extents { get; set; }
public double Scale { get; set; }
public double CanvasWidth { get; set; }
public double CanvasHeight { get; set; }
public CanvasLine(Point dxfStart, Point dxfEnd, string layer)
{
DxfStart= dxfStart;
DxfEnd= dxfEnd;
Layer = layer;
}
public void GetCanvasLines(List<double> extents, double canvasWidth, double canvasHeight)
{
Extents = extents;
CanvasWidth = canvasWidth;
CanvasHeight = canvasHeight;
CanvasStart = DXFToCanvas.DXFCoordToCanvas(DxfStart, Extents, CanvasWidth, CanvasHeight);
CanvasEnd = DXFToCanvas.DXFCoordToCanvas(DxfEnd, Extents, CanvasWidth, CanvasHeight);
}
public partial class MainPage : Page
{
private List<double> extents;
private double scale;
private ObservableCollection<CanvasLine> canvasLines = new ObservableCollection<CanvasLine>();
public List<double> Extents
{
get { return extents; }
set
{
extents = value;
}
}
public double Scale
{
get { return scale; }
set { scale = value; }
}
public ObservableCollection<CanvasLine> CanvasLines
{
get { return canvasLines; }
set
{
canvasLines = value;
}
}
public MainPage()
{
InitializeComponent();
DataContext = this;
}
public void LoadCanvasDXF()
{
extents = LoadDXF.LoadExtents(Globals.CAD_FILE_PATH);
scale = LoadDXF.GetScale(extents, MainPageCanvas.Height, MainPageCanvas.Width);
foreach (CanvasLine canvasLine in Globals.LINE_LIST)
{
canvasLine.GetCanvasLines(Extents, MainPageCanvas.Width, MainPageCanvas.Height);
CanvasLines.Add(canvasLine);
}
}
}
XAML for the ItemsControl:
<ItemsControl ItemsSource="{Binding CanvasLines}" x:Name="MainPageCanvas" Grid.Column="0" Grid.Row="1" Grid.ColumnSpan="2" Width="600" Height="300">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="White" Width="600" Height="300"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Line X1="{Binding CanvasStart.X}" Y1="{Binding CanvasStart.Y}"
X2="{Binding CanvasStart.X}" Y2="{Binding CanvasStart.Y}"
Stroke="Black" StrokeThickness="3"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
Here is an example of a few of the lines start and end:
CanvasStart: 428.88814432501835, 266.5502781209483 CanvasEnd: 349.5791140550308, 266.5502781209483
CanvasStart: 349.5791140550308, 268.2016894748275 CanvasEnd: 428.88814432501835, 268.2016894748275
CanvasStart: 272.29306269353776, 268.2016894748275 CanvasEnd: 341.6523395564147, 268.2016894748275
CanvasStart: 341.6523395564147, 266.5502781209483 CanvasEnd: 272.29306269353776, 266.5502781209483
I tried binding the collection to my ItemsControl but it isn't working.

Related

Bind UserControl Property to ViewModel

I have an UserContol Combination of Country Code Combobox and A number Textbox.
In my Window, I have 2 UserControl (Primary Phone Number and Secondary Phone Number)
Here is my Model
public class ContactNumber
{
public Country Country { get; set; }
public string Number { get; set; }
}
public class Country
{
public int id { get; set; }
public string name { get; set; }
public string code { get; set; }
public string phone_code { get; set; }
public int is_active { get; set; }
public List<Country> country { get; set; }
}
Here is My UserControl XAML
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="90"></ColumnDefinition>
<ColumnDefinition Width="10"></ColumnDefinition>
<ColumnDefinition Width="250"></ColumnDefinition>
</Grid.ColumnDefinitions>
<!--ComboBox for Country-->
<ComboBox Grid.Column="0" Style="{StaticResource ComboBoxMerged}" x:Name="cmbCountry"></ComboBox>
<TextBlock Text="|" FontSize="{StaticResource fontSize30}" Foreground="{StaticResource LightSilverBrush}"
HorizontalAlignment="Center" VerticalAlignment="Top" Grid.Column="1" Margin="0,-5,0,0">
</TextBlock>
<!--TextBox for Number-->
<TextBox Style="{StaticResource TextBoxWithDropDown}"
Text="{Binding ContactNumber.Number,ElementName=ContactWindow,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
x:Name="txtContactNumber" TextChanged="txtContactNumber_TextChanged" Width="240" Grid.Column="2">
</TextBox>
</Grid>
Here is my Control Code Behind
public ContactNumber ContactNumber
{
get { return (ContactNumber)GetValue(ContactNumberProperty); }
set
{
SetValue(ContactNumberProperty, value);
}
}
// Using a DependencyProperty as the backing store for ContactNumber. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ContactNumberProperty =
DependencyProperty.Register("ContactNumber", typeof(ContactNumber), typeof(ContactNumberWithCountryCode),
new FrameworkPropertyMetadata(
null,
FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
SetText));
private static void SetText(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
ContactNumberWithCountryCode contactNumberWithCountryCode=d as ContactNumberWithCountryCode;
if (contactNumberWithCountryCode!=null)
{
contactNumberWithCountryCode.txtContactNumber.Text = (e.NewValue as ContactNumber).Number.ToString();
}
}
public ContactNumberWithCountryCode()
{
InitializeComponent();
}
private void txtContactNumber_TextChanged(object sender, TextChangedEventArgs e)
{
ContactNumber.Number = txtContactNumber.Text;
}
This is my Main Window XAMl
<usercontrols:ContactNumberWithCountryCode ContactNumber="{Binding PrimaryContactNumber,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" x:Name="PracticePhoneNumber" Margin="0,15,0,0" ></usercontrols:ContactNumberWithCountryCode>
<usercontrols:ContactNumberWithCountryCode ContactNumber="{Binding SecondryContactNumber,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}" x:Name="SecondaryPracticePhoneNumber" Margin="0,15,0,0" ></usercontrols:ContactNumberWithCountryCode>
Here is my View Model Code
private ContactNumber primaryContactNumber;
public ContactNumber PrimaryContactNumber
{
get { return primaryContactNumber; }
set
{
primaryContactNumber = value;
OnPropertyChanged("PrimaryContactNumber");
}
}
private ContactNumber secondryContactNumber;
public ContactNumber SecondryContactNumber
{
get { return secondryContactNumber; }
set
{
secondryContactNumber = value;
OnPropertyChanged("SecondryContactNumber");
}
}
My goal is to fill ViewModel Property on Text Or Combobox Value Change.
Thanks in Advance.

ItemsControl items positions issue

Introduction
Hello!
I'm in the process of creating a custom WPF UserControl to display linked nodes (specifically for neural network visualization). I want to provide the UserControl's object source through data binding.
Code
XAML
<Grid Width="{Binding Width}" Height="{Binding Height}">
<StackPanel>
<ItemsControl ItemsSource="{Binding Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<!-- Node container -->
<Canvas Background="AliceBlue"/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Left" Value="{Binding PosX}"/>
<Setter Property="Canvas.Top" Value="{Binding PosY}"/>
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid>
<!-- The Node -->
<Ellipse Width="{Binding Radius}" Height="{Binding Radius}" Fill="{Binding BackColor}" />
<!-- Node Links -->
<ItemsControl ItemsSource="{Binding Links}">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Line Stroke="Black" StrokeThickness="2"
ToolTip="{Binding Tooltip}"
X1="{Binding SourceX}" Y1="{Binding SourceY}"
X2="{Binding DestinationX}" Y2="{Binding DestinationY}"/>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
</StackPanel> </Grid>
Csharp
public class StructureViewModel : BaseViewModel
{
public double Width { get; set; } = 500;
public double Height { get; set; } = 500;
public List<Node> Items { get; set; }
public Canvas SelectedShape { get; set; }
public StructureViewModel()
{
Items = new List<Node>();
var node1 = new Node(100, 150);
var node2 = new Node(100, 180);
node1.AddLink(node2);
Items.Add(node1);
Items.Add(node2);
}
}
public class Node : BaseViewModel
{
public double Radius { get; set; } = 40;
public Brush BackColor { get; set; } = Brushes.Blue;
public double PosX { get; set; } = 0;
public double PosY { get; set; } = 0;
public List<Link> Links { get; set; }
public Node(double posX, double posY)
{
Links = new List<Link>();
PosX = posX;
PosY = posY;
}
public Node(double posX, double posY, List<Link> links)
{
Links = links;
PosX = posX;
PosY = posY;
}
public void AddLink(Node node) => Links.Add(new Link(PosX, PosY, node.PosX, node.PosY));
}
public class Link : BaseViewModel
{
public double SourceX { get; set; }
public double SourceY { get; set; }
public double DestinationX { get; set; }
public double DestinationY { get; set; }
public string ToolTip { get; set; }
public Link(double x1, double y1, double x2, double y2, string tooltip = "")
{
SourceX = x1;
SourceY = y1;
DestinationX = x2;
DestinationY = y2;
ToolTip = tooltip;
}
}
The BaseViewModel implements the property change event through Fody Weaver.
The issue
The Nodes and links are created as expected, although the position of the linking line is incorrect. The linking line is supposed to start from node1 position and end at node2 position.
Tried but failed
I've tried setting the Style TargetType to the Canvas, Grid and other targets, but none worked. Creating a style for the Grid in the DataTemplate didn't help either.
Wrapping up
Please help me solve this issue and most importantly better understand what I was doing wrong. Please let me know if you need any additional information.
Thank you!

Binding Data to UWP WinRT_XamlToolKit_Chart

I am trying to load a chart from a DataTemplate in a UWP program using the WinRT_XamlToolkit_Chart library. I am Binding the Chart Title and Data using the {Binding Property} syntax, but it is not loading the property as a data member of the chart object. I have included both my XAML
<Charting:Chart HorizontalAlignment="Center"
VerticalAlignment="Center"
Width="600"
Height="400"
DataContext="{Binding}"
Title="{Binding Title}">
<Charting:LineSeries Title="{Binding Title}"
Margin="0"
IndependentValuePath="Name"
DependentValuePath="Amount"
IsSelectionEnabled="True"
ItemsSource="{Binding Data}"
/>
</Charting:Chart>
c# Object
public class DataChartNode : ExperimentNode
{
public DataChartNode(String title, String type)
{
Type = type;
Title = title;
Category = "Data Analysis";
}
public DataChartNode(String type)
{
Type = type;
Category = "Data Analysis";
Name = type;
Title = "Hello";
Length = 0;
Data = new List<DataPoint>();
}
public DataChartNode() { }
public string Type { set; get; }
public string Title { set; get; }
public int Length { set; get; }
public List<DataPoint> Data { set; get; }
}
Since you didn't provide the DataPoint class and didn't show how you build the data source that you bind to the Chart control, I wrote a simple demo that created the data source code behind which can work well with your XAML code snippet you can reference.
XAML Code (Same with you)
<Charting:Chart
Title="{Binding Title}"
Width="600"
Height="400"
HorizontalAlignment="Center"
VerticalAlignment="Center"
DataContext="{Binding}">
<Charting:LineSeries
Title="Title"
Margin="0"
DependentValuePath="Amount"
IndependentValuePath="Name"
IsSelectionEnabled="True"
ItemsSource="{Binding Data}" />
</Charting:Chart>
Code behind
public sealed partial class MainPage : Page
{
private Random _random = new Random();
public MainPage()
{
this.InitializeComponent();
var data = new List<DataPoint>();
for (int i = 0; i < 3; i++)
{
data.Add(new DataPoint { Name = "Name" + i, Amount = _random.Next(10, 100) });
}
DataChartNode charnode = new DataChartNode()
{
Title = "Hello",
Data = data
};
this.DataContext = charnode;
}
}
public class DataChartNode
{
public string Type { set; get; }
public string Title { set; get; }
public int Length { set; get; }
public List<DataPoint> Data { set; get; }
}
public class DataPoint
{
public string Name { get; set; }
public int Amount { get; set; }
}
Please check your code behind to find if anything wrong with it.

Binding not working on a single property of an object (while other properties are working)

I'm making a configurable WPF input dialog with the following code:
InputMessageBox.xaml
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:xctk="http://schemas.xceed.com/wpf/xaml/toolkit"
xmlns:local="clr-namespace:MediaManager.Forms" x:Class="MediaManager.Forms.InputMessageBox"
Title="{Binding Title}" Height="{Binding Height}" Width="{Binding Width}">
<Window.Background>
<SolidColorBrush Color="{DynamicResource {x:Static SystemColors.ControlColorKey}}" />
</Window.Background>
<Grid>
<xctk:WatermarkTextBox Watermark="{Binding Message}" Margin="10" VerticalAlignment="Top" TabIndex="0" />
<Button Content="{Binding CancelButtonText}" Width="{Binding ButtonWidth}" Margin="10" HorizontalAlignment="Right" VerticalAlignment="Bottom" IsCancel="True" TabIndex="2" />
<Button Content="{Binding OkButtonText}" Width="{Binding ButtonWidth}" Margin="{Binding MarginOkButton}" HorizontalAlignment="Right" VerticalAlignment="Bottom" IsDefault="True" TabIndex="1" />
</Grid>
InputMessageBox.xaml.cs
public partial class InputMessageBox : Window
{
public InputMessageBox(inputType inputType)
{
InitializeComponent();
switch (inputType)
{
case inputType.AdicionarConteudo:
{
Properties = new InputMessageBoxProperties()
{
ButtonWidth = 75,
CancelButtonText = "Cancelar",
Height = 108,
Message = "Digite o nome do conteudo a ser pesquisado...",
OkButtonText = "Pesquisar",
Title = string.Format("Pesquisar - {0}", Settings.Default.AppName),
Width = 430
};
break;
}
default:
break;
}
DataContext = Properties;
}
public InputMessageBoxProperties Properties { get; set; }
}
InputMessageBoxProperties.cs
public class InputMessageBoxProperties
{
public int ButtonWidth { get; set; }
public string CancelButtonText { get; set; }
public int Height { get; set; }
public string InputText { get; set; }
public Thickness MarginOkButton { get { return new Thickness(10, 10, ButtonWidth + 15, 10); } }
public string Message { get; set; }
public string OkButtonText { get; set; }
public string Title { get; set; }
public int Width { get; set; }
}
When i call it, every binding is working as expected but one, the Width property. When i debug, the width property value is 430, but the width of the frame itself is a lot bigger than that. The confusing part is that the rest of the binding are working. Why is it happening?
You can fix that by setting the Width's Binding Mode to TwoWay :
Width="{Binding Width,Mode=TwoWay}"
You might as well consider implementing the INotifyPropertyChanged interface, so that the UI will automatically be notified in case any changes occurs in those properties :
public class InputMessageBoxProperties:INotifyPropertyChanged
{
private int _width ;
public int Width
{
get
{
return _width;
}
set
{
if (_width == value)
{
return;
}
_width = value;
OnPropertyChanged();
}
}
// add the other properties following the same pattern
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
}

Selected Item not getting for a Listbox inside another Listbox item template

I have a PrimaryItems List & foreach PrimaryItem there is a SecondaryItems list.So i used a ListBox as ItempTemplate of another ListBox.
<ListBox ItemsSource="{Binding PrimaryItems}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<ListBox ItemsSource="{Binding SecondaryItems}" SelectedItem="{Binding SelectedSecondaryItem}" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
My View Model Code
private List<PrimaryItem> _primaryItems;
public List<PrimaryItem> PrimaryItems
{
get { return _primaryItems; }
set { _primaryItems = value;RaisePropertyChanged(); }
}
//SecondaryItems list is inside in each PrimaryItem
//private List<SecondaryItem> _secondaryItems;
//public List<SecondaryItem> SecondaryItems
//{
// get { return _secondaryItems; }
// set { _secondaryItems = value; RaisePropertyChanged(); }
//}
private SecondaryItem _selectedSecondaryItem;
public SecondaryItem SelectedSecondaryItem
{
get { return _selectedSecondaryItem; }
set
{
_selectedSecondaryItem = value;
if (_selectedSecondaryItem != null)
{
//TO DO
}
}
}<br/>
This is the class structure
public class PrimaryItem
{
public int Id { get; set; }
public string Name { get; set; }
public List<SecondaryItem> SecondaryItems{ get; set; }
}
public class SecondaryItem
{
public int Id { get; set; }
public string Name { get; set; }
}
and I set SelectedItem Binding to the Second ListBox.
But am not getting the Selection Trigger on Second ListBox.
Can we use a ListBox inside another ListBox` Template ? If yes how do we overcome this problem?
First of all, use ObservableCollection instead of List since it implements INotifyPropertyChanged interface.
As far as I understand your requirements, PrimaryItem class should has a property SecondaryItems. So remove it from ViewModel and paste to PrimaryItem class (as well as SelectedSecondaryItem property):
private ObservableCollection<SecondaryItem> _secondaryItems;
public ObservableCollection<SecondaryItem> SecondaryItems
{
get { return _secondaryItems; }
set { _secondaryItems = value; RaisePropertyChanged(); }
}
EDIT:
I've fully reproduced your situation and get it working.
Classes:
public class PrimaryItem
{
public int Id { get; set; }
public string Name { get; set; }
public List<SecondaryItem> SecondaryItems { get; set; }
private SecondaryItem _selectedSecondaryItem;
public SecondaryItem SelectedSecondaryItem
{
get { return _selectedSecondaryItem; }
set
{
_selectedSecondaryItem = value;
if (_selectedSecondaryItem != null)
{ // My breakpoint here
//TO DO
}
}
}
}
public class SecondaryItem
{
public int Id { get; set; }
public string Name { get; set; }
}
ViewModel:
public class MyViewModel : ViewModelBase
{
private List<PrimaryItem> _primaryItems;
public List<PrimaryItem> PrimaryItems
{
get { return _primaryItems; }
set { _primaryItems = value; RaisePropertyChanged("PrimaryItems"); }
}
public ErrorMessageViewModel()
{
this.PrimaryItems = new List<PrimaryItem>
{
new PrimaryItem
{
SecondaryItems =
new List<SecondaryItem>
{
new SecondaryItem { Id = 1, Name = "First" },
new SecondaryItem { Id = 2, Name = "Second" },
new SecondaryItem { Id = 3, Name = "Third" }
},
Name = "FirstPrimary",
Id = 1
}
};
}
}
View:
<Window x:Class="TestApp.Views.MyView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:vm="clr-namespace:TestApp.ViewModels;assembly=TestApp.ViewModels"
xmlns:my="http://schemas.microsoft.com/wpf/2008/toolkit"
Title="Title" Height="240" Width="270" ResizeMode="NoResize"
WindowStartupLocation="CenterOwner" WindowStyle="ToolWindow">
<Window.DataContext>
<vm:MyViewModel/>
</Window.DataContext>
<Grid>
<ListBox ItemsSource="{Binding PrimaryItems}">
<ListBox.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding Name}"/>
<ListBox ItemsSource="{Binding SecondaryItems}" SelectedItem="{Binding SelectedSecondaryItem}" ScrollViewer.VerticalScrollBarVisibility="Disabled" ScrollViewer.HorizontalScrollBarVisibility="Disabled">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</StackPanel>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
You can try to use LinqToVisualTree, it can get alomost all Controls in your app, you just have to select what you want to find(in your case ListBoxItem), and then cast it to your model. I used it, when I needed to get text from TextBox which was in ListboxItem. But it also fits to your task.

Categories

Resources