Change width of ItemsControl cells on button click - wpf

I am trying to create a table whose cells are dynamic in width and height. Following is my xaml code:
<ItemsControl Grid.Row="1" Grid.Column="1" DataContext="{Binding GameBoardApp}" ItemsSource="{Binding BlockList}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel></WrapPanel>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Row" Value="{Binding Row}"/>
<Setter Property="Grid.Column" Value="{Binding Col}"/>
<Setter Property="Grid.Width" Value="{Binding Width, Mode=TwoWay}" />
<Setter Property="Grid.Height" Value="{Binding Height, Mode=TwoWay}" />
</Style>
</ItemsControl.ItemContainerStyle>
<ItemsControl.ItemTemplate>
<DataTemplate>
<Border BorderThickness="1" BorderBrush="Black">
<Grid>
<Rectangle Fill="{Binding Background}" />
<TextBlock Text="{Binding Name}"/>
</Grid>
</Border>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
I am able to design the UI and see the content but I am not able to set up 2-way data binding to change the width of the cell. Following is my Code Behind:
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
GameBoardApp = new GameBoard(50);
DataContext = this;
}
public GameBoard GameBoardApp { get; set; }
private void IncreaseSize_Click(object sender, RoutedEventArgs e)
{
GameBoardApp = new GameBoard(GameBoardApp.CellWidth + 1);
Debug.Print(GameBoardApp.CellWidth.ToString());
}
private void DecreaseSize_Click(object sender, RoutedEventArgs e)
{
GameBoardApp = new GameBoard(GameBoardApp.CellWidth-1);
Debug.Print(GameBoardApp.CellWidth.ToString());
}
}
public class GameBoard : INotifyPropertyChanged
{
public GameBoard(int cellWidthVal)
{
_cellWidth = cellWidthVal;
var m1 = new Block() { Name = "b1", Background = Brushes.Red, Col = 50, Row = 50, Width = CellWidth };
var m2 = new Block() { Name = "b2", Background = Brushes.Gray, Col = 50, Row = 50, Width = CellWidth };
var m3 = new Block() { Name = "b3", Background = Brushes.Goldenrod, Col = 0, Row = 0, Width = CellWidth };
var m4 = new Block() { Name = "b4", Background = Brushes.Honeydew, Col = 0, Row = 0, Width = CellWidth };
var m5 = new Block() { Name = "b5", Background = Brushes.Bisque, Col = 70, Row = 70, Width = CellWidth };
var m6 = new Block() { Name = "b6", Background = Brushes.Honeydew, Col = 0, Row = 0, Width = CellWidth };
var m7 = new Block() { Name = "b7", Background = Brushes.Honeydew, Col = 0, Row = 0, Width = CellWidth };
var m8 = new Block() { Name = "b1", Background = Brushes.Red, Col = 0, Row = 0, Width = CellWidth };
var m9 = new Block() { Name = "b2", Background = Brushes.Gray, Col = 0, Row = 0, Width = CellWidth };
var m10 = new Block() { Name = "b3", Background = Brushes.Goldenrod, Col = 0, Row = 0, Width = CellWidth };
var m11 = new Block() { Name = "b4", Background = Brushes.Honeydew, Col = 0, Row = 0, Width = CellWidth };
var m12 = new Block() { Name = "b5", Background = Brushes.Honeydew, Col = 0, Row = 0, Width = CellWidth };
var m13 = new Block() { Name = "b6", Background = Brushes.Honeydew, Col = 0, Row = 0, Width = CellWidth };
var m14 = new Block() { Name = "bhg jg7", Background = Brushes.Honeydew, Col = 0, Row = 0, Width = CellWidth };
_blockList = new ObservableCollection<Block>() { m1, m2, m3, m4, m5, m6, m7, m8, m9, m10, m11};
}
int _cellWidth;
public int CellWidth { get { return _cellWidth; } set { _cellWidth = value; RaisePropertyChanged("CellWidth"); } }
ObservableCollection<Block> _blockList;
public ObservableCollection<Block> BlockList { get { return _blockList; } set { _blockList = value; RaisePropertyChanged("BlockList"); } }
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged(string propname)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname));
}
}
public class Block : INotifyPropertyChanged
{
int _row;
public int Row { get { return _row; } set { _row = value; RaisePropertyChanged("Row"); } }
int _col;
public int Col { get { return _col; } set { _col = value; RaisePropertyChanged("Col"); } }
string _name;
public string Name { get { return _name; } set { _name = value; RaisePropertyChanged("Name"); } }
Brush _background;
public Brush Background { get { return _background; } set { _background = value; RaisePropertyChanged("Background"); } }
int _width = 50;
public int Width { get { return _width; } set { _width = value; RaisePropertyChanged("Width"); } }
int _height = 50;
public int Height { get { return _height; } set { _height = value; RaisePropertyChanged("Width"); } }
public event PropertyChangedEventHandler PropertyChanged;
void RaisePropertyChanged(string propname)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propname));
}
}
I am trying to refresh the ItemControl once I make the changes in GameBoard but not able to do it.
Preferably I would want to change the width with only one width variable in GameBoard class but looks like that will not be possible here
Regards

Fix your ItemContainerStyle to target the ContentPresenter and bind its Width and Height properties to your source properties:
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Width" Value="{Binding Width}" />
<Setter Property="Height" Value="{Binding Height}" />
</Style>
</ItemsControl.ItemContainerStyle>
And since you are creating a new GameBoard object in your click event handlers, you also need to implement the INotifyPropertyChanged interface and raise change notifications in the window:
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
GameBoardApp = new GameBoard(50);
DataContext = this;
}
private GameBoard _gameBoardApp;
public GameBoard GameBoardApp
{
get { return _gameBoardApp; }
set { _gameBoardApp = value; RaisePropertyChanged(); }
}
private void IncreaseSize_Click(object sender, RoutedEventArgs e)
{
GameBoardApp = new GameBoard(GameBoardApp.CellWidth + 1);
Debug.Print(GameBoardApp.CellWidth.ToString());
}
private void DecreaseSize_Click(object sender, RoutedEventArgs e)
{
GameBoardApp = new GameBoard(GameBoardApp.CellWidth - 1);
Debug.Print(GameBoardApp.CellWidth.ToString());
}
public event PropertyChangedEventHandler PropertyChanged;
private void RaisePropertyChanged([CallerMemberName] string propertyName = "")
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
This should make your example work as expected.
As a side note, the Grid.Row and Grid.Column attached properties are not useful when you host your item containers in a WrapPanel.

Related

ComboBox binding to ObservableCollection is not working

I am new to WPF. In existing application,Combo box is not getting binding values from ObservableCollection. I have a class ShipmentItem. I need to bind combo box with WeightUnit field.
below is the code:
public partial class ShipmentItem : DataEntity {
private int piecesField;
private float weightField;
private System.Nullable<float> widthField;
private System.Nullable<float> lengthField;
private System.Nullable<float> heightField;
private string descriptionField;
private WeightUnit weightUnitField;
private LengthUnit lengthUnitField;
public int Pieces {
get {
return this.piecesField;
}
set {
this.piecesField = value;
this.RaisePropertyChanged("Pieces");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=1)]
public float Weight {
get {
return this.weightField;
}
set {
this.weightField = value;
this.RaisePropertyChanged("Weight");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Order=2)]
public System.Nullable<float> Width {
get {
return this.widthField;
}
set {
this.widthField = value;
this.RaisePropertyChanged("Width");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Order=3)]
public System.Nullable<float> Length {
get {
return this.lengthField;
}
set {
this.lengthField = value;
this.RaisePropertyChanged("Length");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(IsNullable=true, Order=4)]
public System.Nullable<float> Height {
get {
return this.heightField;
}
set {
this.heightField = value;
this.RaisePropertyChanged("Height");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=5)]
public string Description {
get {
return this.descriptionField;
}
set {
this.descriptionField = value;
this.RaisePropertyChanged("Description");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=6)]
public WeightUnit WeightUnit {
get {
return this.weightUnitField;
}
set {
this.weightUnitField = value;
this.RaisePropertyChanged("WeightUnit");
}
}
/// <remarks/>
[System.Xml.Serialization.XmlElementAttribute(Order=7)]
public LengthUnit LengthUnit {
get {
return this.lengthUnitField;
}
set {
this.lengthUnitField = value;
this.RaisePropertyChanged("LengthUnit");
}
}}
Here is the observable collection :
public ObservableCollection<ShipmentItem> ShipmentItemCollection
{
get { return shipmentItemCollection; }
set { shipmentItemCollection = (ObservableCollection<ShipmentItem>)value; }
}
shipmentItemCollection.Add(new ShipmentItem()
{
Weight = 0,
Pieces = 0,
WeightUnit = WeightUnit.Pounds,
Description = string.Empty,
Length = 0,
Width = 0,
Height = 0,
LengthUnit = LengthUnit.Inches,
Skidded = false,
Stackable = false,
Nmfc = string.Empty,
FreightClass = string.Empty,
DeliveryStop = 0
});
shipmentItemList.ItemsSource = shipmentItemCollection;
shipmentItemList.DataContext = ShipmentItemCollection;
ShipmentItemList is Listview, which has text box and combo box.Text box are getting their values from the binding path except ComboBox.And this is the XAML code for combo box.
<ComboBox Name ="cmbWeightUnits"
SelectionChanged="cmbWeightUnits_SelectionChanged"
PreviewKeyDown="check_PreviewKeyDown"
ItemsSource="{Binding Path= ShipmentItemCollection}"
DisplayMemberPath="{Binding Path=WeightUnit}">
</ComboBox>
Any help would be appreciated.
View
<ComboBox ItemsSource="{Binding ShipmentItemCollection}"
DisplayMemberPath="{Binding Path=WeightUnit}">
</ComboBox>
In the View class, set the DataContext to ViewModel
ViewModel
private ObservableCollection<ShipmentItem> _shipmentItemCollection;
public ObservableCollection<ShipmentItem> ShipmentItemCollection
{
get { return _shipmentItemCollection; }
set { _shipmentItemCollection = value; }
}
continued (in a constructor or some method)
ShipmentItemCollection.Add(new ShipmentItem()
{
Weight = 0,
Pieces = 0,
WeightUnit = WeightUnit.Pounds,
Description = string.Empty,
Length = 0,
Width = 0,
Height = 0,
LengthUnit = LengthUnit.Inches,
Skidded = false,
Stackable = false,
Nmfc = string.Empty,
FreightClass = string.Empty,
DeliveryStop = 0
});

How to give link to nodes in Treeview?

I want to develop a WPF application like below image,..In that application i need to connect two child nodes of treeview( child nodes connected through blue color line).
How can i do it?
Here is what I came up. You'll need to define your on way of how to find matches, I just mocked it with the header value.
It's very rough and could do with some love, but I believe it does what you're after.
<Window x:Class="WpfApplication64.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" WindowStartupLocation="CenterScreen">
<DockPanel>
<Button Content="AddNode"
Click="AddNodeClick"
DockPanel.Dock="Top" />
<TreeView BorderThickness="1"
BorderBrush="Black"
Name="treeView"
Width="300">
<TreeView.ItemContainerStyle>
<Style TargetType="{x:Type TreeViewItem}"
BasedOn="{StaticResource {x:Type TreeViewItem}}">
<Setter Property="IsExpanded"
Value="True" />
</Style>
</TreeView.ItemContainerStyle>
</TreeView>
</DockPanel>
namespace WpfApplication64
{
class TreeViewLinksAdorner : Adorner
{
public TreeViewLinksAdorner(TreeView adornedElement) :
base(adornedElement)
{
SnapsToDevicePixels = true;
adornedElement.AddHandler(TreeViewItem.CollapsedEvent, new RoutedEventHandler(OnIsExpandedChanged));
adornedElement.AddHandler(TreeViewItem.ExpandedEvent, new RoutedEventHandler(OnIsExpandedChanged));
}
void OnIsExpandedChanged(object sender, RoutedEventArgs e)
{
InvalidateVisual();
}
protected override void OnRender(DrawingContext drawingContext)
{
Brush[] colours = new Brush[] { Brushes.Red, Brushes.Green, Brushes.Blue };
TreeView treeView = (TreeView)AdornedElement;
var treeViewItems = GetVisibleTreeViewItems(treeView);
var processed = new HashSet<string>();
double offset = 6;
int brushIndex = 0;
double width = treeView.ActualWidth - SystemParameters.ScrollWidth;
foreach (var tvi1 in treeViewItems)
{
if(processed.Contains(tvi1.Header.ToString()))
{
continue;
}
bool found = false;
foreach (var tvi2 in treeViewItems)
{
if (tvi1 == tvi2)
{
continue;
}
else if(tvi1.Header.ToString() == tvi2.Header.ToString())
{
Pen pen = new Pen(colours[brushIndex], 1) { DashStyle = DashStyles.Dash };
Point a = LocalPosToAncestorPos((ContentPresenter)tvi1.Template.FindName("PART_Header", tvi1), treeView);
Point d = LocalPosToAncestorPos((ContentPresenter)tvi2.Template.FindName("PART_Header", tvi2), treeView);
Point b = new Point(width - offset, a.Y);
Point c = new Point(width - offset, d.Y);
drawingContext.DrawLine(pen, a, b);
drawingContext.DrawLine(pen, b, c);
drawingContext.DrawLine(pen, c, d);
found = true;
}
}
if(found)
{
brushIndex = brushIndex < colours.Length - 1 ? brushIndex + 1 : 0;
offset += 6;
}
processed.Add(tvi1.Header.ToString());
}
}
Point LocalPosToAncestorPos(FrameworkElement child, FrameworkElement ancestor)
{
Point localPos = new Point(child.ActualWidth, child.ActualHeight * 0.5);
return child.TransformToAncestor(ancestor).Transform(localPos);
}
List<TreeViewItem> GetVisibleTreeViewItems(FrameworkElement parent)
{
var treeViewItems = new List<TreeViewItem>();
for (int i = 0, count = VisualTreeHelper.GetChildrenCount(parent); i < count; i++)
{
FrameworkElement child = VisualTreeHelper.GetChild(parent, i) as FrameworkElement;
var treeViewItem = child as TreeViewItem;
if (treeViewItem != null)
{
treeViewItems.Add(treeViewItem);
if (treeViewItem.IsExpanded)
{
foreach (var childTreeViewItem in GetVisibleTreeViewItems(child))
{
treeViewItems.Add(childTreeViewItem);
}
}
}
else
{
foreach (var childTreeViewItem in GetVisibleTreeViewItems(child))
{
treeViewItems.Add(childTreeViewItem);
}
}
}
return treeViewItems;
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
Loaded += OnLoaded;
InitializeComponent();
AddNode();
AddNode();
}
void OnLoaded(object sender, RoutedEventArgs e)
{
AdornerLayer.GetAdornerLayer(treeView).Add(new TreeViewLinksAdorner(treeView));
}
void AddNodeClick(object sender, RoutedEventArgs e)
{
AddNode();
}
void AddNode()
{
TreeViewItem parent = new TreeViewItem() { Header = "item" + treeView.Items.Count };
parent.Items.Add(new TreeViewItem() { Header = "subItem" + subCount++ });
parent.Items.Add(new TreeViewItem() { Header = "subItem" + subCount++ });
parent.Items.Add(new TreeViewItem() { Header = "$" });
parent.Items.Add(new TreeViewItem() { Header = "subItem" + subCount++ });
parent.Items.Add(new TreeViewItem() { Header = "$$" });
parent.Items.Add(new TreeViewItem() { Header = "$$$" });
parent.Items.Add(new TreeViewItem() { Header = "subItem" + subCount++ });
parent.Items.Add(new TreeViewItem() { Header = "$$$$" });
treeView.Items.Add(parent);
}
int subCount;
}
}

2 Dimensional Dynamic Listview With Textbox

This a dynamic listview with dynamic header and rows. But the problem here is wen i try to use a textbox as
xaml = "<DataTemplate><TextBox VerticalAlignment=\"Center\" TextChanged=\"{Binding " + propName + "}\" > " + propName + "</TextBox></DataTemplate>";
instead of a checkbox with a binding in the method CreateDataTemplate the values can't be extratcted after the btn is clicked.
Here is the code with CheckBox. So can anybody plz help me out. and i also need the values which will be inside the textbox. Thank you in advance
<Window x:Class="WpfListView.SalesPerson_SalesRegion_Association"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="SalesPerson_SalesRegion_Association" Height="500" Width="500">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<ListView Name="listView1" Width="400" Height="300" Margin="20" HorizontalAlignment="Left">
<ListView.View>
<GridView></GridView>
</ListView.View>
</ListView>
<Button Grid.Row="1" HorizontalAlignment="Left"
Content="ShowSelectedMapping"
Name="btnShow" Width="150" Margin="0,10,0,0" Click="btnShow_Click"></Button>
<TextBlock Name="textBlock1" Grid.Row="2"
HorizontalAlignment="Left" Margin="0,10,0,0"></TextBlock>
</Grid>
public partial class SalesPerson_SalesRegion_Association : Window
{
public SalesPerson_SalesRegion_Association()
{
InitializeComponent();
AddColumnsToListView();
DataTable dt = DataHelper.GetRegionPersonAssociation();
listView1.ItemsSource = dt.DefaultView;
}
private void btnShow_Click(object sender, RoutedEventArgs e)
{
DataView view = listView1.ItemsSource as DataView;
DataTable userSelectionTbl = view.ToTable();
DataTable idTable = DataHelper.GetRegionIdPersonIdMatrix();
List<SalesRegion> lstRegion = SalesRegion.GetRegions();
string selectedRegion = string.Empty;
string msg = string.Empty;
DataRow dRow=null;
int totRows = userSelectionTbl.Rows.Count;
int totCols = lstRegion.Count-1;
string strTempMsg = string.Empty;
bool isColChecked = false;
for (int rowIndex = 0; rowIndex < totRows; rowIndex++)
{
dRow = userSelectionTbl.Rows[rowIndex];
strTempMsg = dRow[0].ToString() + "(" + idTable.Rows[rowIndex][0].ToString() + ")" + " : ";
string rgnId="";
isColChecked = false;
foreach (SalesRegion region in lstRegion)
{
if (((bool)dRow[region.RegionName]) == true)
{
rgnId = idTable.Rows[rowIndex][region.RegionName].ToString();
strTempMsg += region.RegionName + "(" + rgnId + ")";
isColChecked = true; }
}
if (isColChecked == false)
{
strTempMsg += " : No region selected";
}
strTempMsg += Environment.NewLine;
msg += strTempMsg;
}
textBlock1.Text = msg;
string tt = "t";
}
private void AddColumnsToListView()
{
List<SalesRegion> lstSalesRegion = SalesRegion.GetRegions();
List<SalesPerson> lstSalesPerson = SalesPerson.GetSalesPersons();
GridViewColumn colSalesPerson = new GridViewColumn();
colSalesPerson.Header = "Sales Person";
colSalesPerson.DisplayMemberBinding = new Binding("SalesPersonName");
colSalesPerson.Width = 150;
GridView grdView = listView1.View as GridView;
grdView.Columns.Add(colSalesPerson);
//Since columns are dynamic we need a data template per column
// in which we bind the checkBox's checked property with
//appropriate columnName
Dictionary<string, DataTemplate> dict = GetDataTemplates(lstSalesRegion);
foreach (SalesRegion region in lstSalesRegion)
{
GridViewColumn col1 = new GridViewColumn();
col1.Header = region.RegionName;
DataTemplate dTempl = dict[region.RegionName];
col1.CellTemplate = dTempl;
grdView.Columns.Add(col1);
}
}
private Dictionary<string, DataTemplate> GetDataTemplates(List<SalesRegion> lstSalesRegion)
{
Dictionary<string, DataTemplate> dict = new Dictionary<string, DataTemplate>();
foreach (SalesRegion region in lstSalesRegion)
{
DataTemplate dTemplate = CreateDataTemplate(region.RegionName);
dict.Add(region.RegionName, dTemplate);
}
return dict;
}
private DataTemplate CreateDataTemplate(string propName)
{
MemoryStream sr = null;
ParserContext pc = null;
string xaml = string.Empty;
xaml = "<DataTemplate><CheckBox VerticalAlignment=\"Center\" IsChecked=\"{Binding " + propName + "}\"></CheckBox></DataTemplate>";
sr = new MemoryStream(Encoding.ASCII.GetBytes(xaml));
pc = new ParserContext();
pc.XmlnsDictionary.Add("", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
pc.XmlnsDictionary.Add("x", "http://schemas.microsoft.com/winfx/2006/xaml");
DataTemplate datatemplate = (DataTemplate)XamlReader.Load(sr, pc);
return datatemplate;
}
} // class ends here
} // DataHelper classes
public class SalesPerson
{
public int SalesPersonId
{ get; set; }
public string SalesPersonName
{ get; set; }
public SalesPerson(int salesPersonId, string salesPersonName)
{
this.SalesPersonId = salesPersonId;
this.SalesPersonName = salesPersonName;
}
public static List<SalesPerson> GetSalesPersons()
{
List<SalesPerson> lst = new List<SalesPerson>();
lst.Add(new SalesPerson(101, "SalesPerson1"));
lst.Add(new SalesPerson(201, "SalesPerson2"));
lst.Add(new SalesPerson(301, "SalesPerson3"));
lst.Add(new SalesPerson(401, "SalesPerson4"));
lst.Add(new SalesPerson(501, "SalesPerson5"));
return lst;
}
} // class SalesPerson ends here
public class SalesRegion
{
public int RegionId
{ get; set; }
public string RegionName
{ get; set; }
public SalesRegion(int regionId, string regionName)
{
this.RegionId = regionId;
this.RegionName = regionName;
}
public static List<SalesRegion> GetRegions()
{
List<SalesRegion> lst = new List<SalesRegion>();
lst.Add(new SalesRegion(501,"North"));
lst.Add(new SalesRegion(502, "South"));
lst.Add(new SalesRegion(503, "East"));
lst.Add(new SalesRegion(504, "West"));
lst.Add(new SalesRegion(505, "MyRegion"));
return lst;
}
} // class SalesRegion ends here
public class DataHelper
{
public static DataTable GetRegionPersonAssociation()
{
DataTable dt = new DataTable();
//Create data table structure
// SalesPerson Region1 Region2 Region3 ....
DataColumn colSalesPerson = new DataColumn("SalesPersonName", typeof(string));
dt.Columns.Add(colSalesPerson);
List<SalesRegion> lstRegions = SalesRegion.GetRegions();
DataColumn colRegion = null;
foreach (SalesRegion region in lstRegions)
{
colRegion = new DataColumn(region.RegionName, typeof(bool));
dt.Columns.Add(colRegion);
}
//Fill data into the data table
List<SalesPerson> personList = SalesPerson.GetSalesPersons();
DataRow dRow = null;
foreach (SalesPerson sp in personList)
{
dRow = dt.NewRow();
dRow["SalesPersonName"] = sp.SalesPersonName;
foreach (SalesRegion sr in lstRegions)
{
dRow[sr.RegionName] = false;
}
dt.Rows.Add(dRow);
}
return dt;
}
public static DataTable GetRegionIdPersonIdMatrix()
{
DataTable dt = new DataTable();
//Create data table structure
// SalesPerson Region1 Region2 Region3 ....
DataColumn colSalesPerson = new DataColumn("SalesPersonId", typeof(int));
dt.Columns.Add(colSalesPerson);
List<SalesRegion> lstRegions = SalesRegion.GetRegions();
DataColumn colRegion = null;
foreach (SalesRegion region in lstRegions)
{
colRegion = new DataColumn(region.RegionName, typeof(int));
dt.Columns.Add(colRegion);
}
//Fill data into the data table
List<SalesPerson> personList = SalesPerson.GetSalesPersons();
DataRow dRow = null;
foreach (SalesPerson sp in personList)
{
dRow = dt.NewRow();
dRow["SalesPersonId"] = sp.SalesPersonId;
foreach (SalesRegion sr in lstRegions)
{
dRow[sr.RegionName] = sr.RegionId;
}
dt.Rows.Add(dRow);
}
return dt;
} } // class DataHelper ends here
use a textbox data template like this
xaml = "<DataTemplate><TextBox VerticalAlignment=\"Center\" Tag=\"{Binding " + propName + ", Mode=TwoWay}\" > " + propName + "</TextBox></DataTemplate>";
add a style for textboxes to your listview.resources
<Style TargetType="{x:Type TextBox}">
<EventSetter Event="TextChanged" Handler="TextBox_TextChanged"></EventSetter>
</Style>
add the handler to your codebehind
private void TextBox_TextChanged(object sender, TextChangedEventArgs e)
{
(sender as TextBox).Tag = true;
}
this will behave like your checkbox example.

Zooming To Mouse Point With ScrollView and ViewBox in Wpf

I have some paths drawn to the screen in wpf. The coordinates being used are quite small so they have been made to fill the screen with a view box. I am now trying to implement pan and zoom functionality. I would like to be able to zoom to wherever the mouse is in relation to the ui (i.e zoomed screen center is equal to mouse coordinates). The current outcome is that the center of the screen when zoomed is not reflective of the exact mouse position on the ui.
If you want to see what is happening... Here is my current solution file.
Or
Heres some code:
View Xaml
<Grid Name="MasterGrid" DataContext="{StaticResource mainWindowViewModel}">
<ScrollViewer HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Visible" Name="VisualisationScroller">
<Viewbox Name="VisualisationBox" Stretch="Fill" Loaded="VisualisationBox_Loaded">
<ItemsControl Name="CustomDrawingElement" ItemsSource="{Binding Trajectories}" Width="{Binding VisualisationWidth}" Height="{Binding VisualisationHeight}">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="data:VisualisedTrajectory">
<Path Data = "{Binding PathData}" Stroke="Red" StrokeThickness="0.001" Fill="Transparent" />
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas
Background="DarkGray"
IsItemsHost="True">
</Canvas>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.RenderTransform>
<TransformGroup>
<ScaleTransform ScaleX="1" ScaleY="1" />
<TranslateTransform />
</TransformGroup>
</ItemsControl.RenderTransform>
</ItemsControl>
</Viewbox>
</ScrollViewer>
</Grid>
View Model
public class MainWindowViewModel : BaseViewModel
{
public MainWindowViewModel()
{
VisualiseRawTrajectories();
}
private ObservableCollection<VisualisedTrajectory> _trajectories = new ObservableCollection<VisualisedTrajectory>();
public ObservableCollection<VisualisedTrajectory> Trajectories
{
get { return _trajectories; }
}
#region VisualisationDimensions
private double _visualisationWidth = 100;
public double VisualisationWidth
{
get { return _visualisationWidth; }
private set { _visualisationWidth = value; }
}
private double _visualisationHeight = 100;
public double VisualisationHeight
{
get { return _visualisationHeight; }
private set { _visualisationHeight = value; }
}
#endregion
public void VisualiseRawTrajectories()
{
var rand = new Random();
for (int i = 0; i < 5; i++)
{
var currentTrajectorySet = new List<Point>(); //each time through reinitialise
for (int j = 0; j < 5; j++)
{
currentTrajectorySet.Add(new Point(rand.NextDouble() * 0.5, rand.NextDouble() * 0.5)); //add a new point with max 0.5
if(j == 4)
{
currentTrajectorySet.Add(new Point(0.5, 0.5)); //for good measure :)
_trajectories.Add(new VisualisedTrajectory(CreatePathData(currentTrajectorySet)));
}
}
}
VisualisationHeight = 0.5;
VisualisationWidth = 0.5; //just for demonstration purposes
OnPropertyChanged("VisualisationHeight");
OnPropertyChanged("VisualisationWidth");
}
private Geometry CreatePathData(IList<Point> points)
{
var geometry = new StreamGeometry {FillRule = FillRule.EvenOdd};
using (StreamGeometryContext ctx = geometry.Open())
{
ctx.BeginFigure(points[0], false, false); //use the first index
ctx.PolyLineTo(points, true, true);
}
return (Geometry)geometry.GetAsFrozen();
}
}
View Code Behind
public MainWindow()
{
InitializeComponent();
VisualisationScroller.PreviewMouseWheel += OnPreviewMouseWheel;
}
private Point originalDimensions;
private void VisualisationBox_Loaded(object sender, RoutedEventArgs e)
{
Viewbox viewBox = sender as Viewbox;
viewBox.Width = viewBox.ActualWidth;
viewBox.Height = viewBox.ActualHeight;
originalDimensions = new Point(viewBox.ActualWidth, viewBox.ActualHeight);
}
#region Zoom
private int _numberDrawnItems = 0;
private void OnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
var zoomScale = new Point(CustomDrawingElement.RenderTransform.Value.M11,
CustomDrawingElement.RenderTransform.Value.M22); //gets the scale x and scale y
if (CustomDrawingElement != null && _numberDrawnItems != CustomDrawingElement.Items.Count) //if there was something draw to screen
{
_numberDrawnItems = CustomDrawingElement.Items.Count;
CustomDrawingElement.RenderTransformOrigin = new Point(0.5, 0.5); //if not set zoom from center
}
if (e.Delta > 0)
{
if (CustomDrawingElement != null)
{
VisualisationBox.Width = originalDimensions.X * (zoomScale.X + 1);
VisualisationBox.Height = originalDimensions.Y * (zoomScale.Y + 1);
var mousePosition = e.GetPosition(MasterGrid);
CustomDrawingElement.RenderTransformOrigin = new Point(mousePosition.X / MasterGrid.ActualWidth, mousePosition.Y / MasterGrid.ActualHeight);
CustomDrawingElement.RenderTransform = new MatrixTransform(zoomScale.X + 1, 0, 0, zoomScale.Y + 1, 0, 0);
}
}
if (e.Delta < 0)
{
if (zoomScale.X > 1 && zoomScale.Y > 1) //stops you from zooming out too much
{
if (CustomDrawingElement != null)
{
VisualisationBox.Width = VisualisationBox.Width - originalDimensions.X;
VisualisationBox.Height = VisualisationBox.Height - originalDimensions.Y;
CustomDrawingElement.RenderTransform = new MatrixTransform(zoomScale.X - 1, 0, 0, zoomScale.Y - 1, 0, 0);
}
}
}
e.Handled = true;
}
#endregion //Zooming code
}
Solved it changed the back code for zooming the View to:
if (e.Delta > 0)
{
if (CustomDrawingElement != null)
{
//zoom
_zoomScale++; //increase it now that we have zoomed
VisualisationBox.Width = _originalDimensions.X * (_zoomScale);
VisualisationBox.Height = _originalDimensions.Y * (_zoomScale);
ScrollerDimensions.Content = VisualisationScroller.ActualWidth + "x" + VisualisationScroller.ActualHeight;
BoxDimensions.Content = VisualisationBox.ActualWidth + "x" + VisualisationBox.ActualHeight;
var mousePosition = e.GetPosition(MasterGrid);
mousePosition = MasterGrid.TransformToVisual(VisualisationBox).Transform(mousePosition);
ScrolledPoint.Content = mousePosition.X + "," + mousePosition.Y;
VisualisationScroller.ScrollToHorizontalOffset(mousePosition.X);
VisualisationScroller.ScrollToVerticalOffset(mousePosition.Y);
}
}
if (e.Delta < 0)
{
if (_zoomScale > 1) //stops you from zooming out too much
{
if (CustomDrawingElement != null)
{
var mousePosition = e.GetPosition(MasterGrid);
_zoomScale -= 1; //decrease the zoom
VisualisationBox.Width = VisualisationBox.Width - _originalDimensions.X;
VisualisationBox.Height = VisualisationBox.Height - _originalDimensions.Y;
mousePosition = MasterGrid.TransformToVisual(VisualisationBox).Transform(mousePosition);
mousePosition = new Point(mousePosition.X - _originalDimensions.X, mousePosition.Y - _originalDimensions.Y);
VisualisationScroller.ScrollToHorizontalOffset(mousePosition.X);
VisualisationScroller.ScrollToVerticalOffset(mousePosition.Y);
}
}
}
e.Handled = true;
If anyone is interested HERE is the finished solution file with panning implemented too.

ListView Binding with "IsSelected" Property of ListViewItem

I have following class
public abstract class AbsTrinityEvent
{
public event IsSelected OnSelectedEvent;
bool _IsSelected;
ITrinityEvent _objTrinityEvent;
public AbsTrinityEvent(ITrinityEvent objTrinityEvent)
{
_objTrinityEvent = objTrinityEvent;
}
public ITrinityEvent TrinityEventObj
{
set
{
_objTrinityEvent = value;
}
get
{
return _objTrinityEvent;
}
}
public int EventRefID
{
get
{
return _objTrinityEvent.EventRefID;
}
}
public string EventDescription
{
get
{
return _objTrinityEvent.EventDescription;
}
}
public string EventDateTime
{
get
{
return _objTrinityEvent.EventDateTime;
}
}
public string Site
{
get
{
return _objTrinityEvent.Site;
}
}
public int Priority
{
get
{
return _objTrinityEvent.Priority;
}
}
public string DeviceName
{
get
{
return _objTrinityEvent.DeviceName;
}
}
public bool IsAlarm
{
get
{
return _objTrinityEvent.IsAlarm;
}
}
public string OperatorName
{
get
{
return _objTrinityEvent.OperatorName;
}
}
public int SiteID
{
get
{
return _objTrinityEvent.SiteID;
}
}
public int EventSrcInstanceID
{
get
{
return _objTrinityEvent.EventSrcInstanceID;
}
}
public int EventSrcInstanceMasterDeviceID
{
get
{
return _objTrinityEvent.EventSrcInstanceMasterDeviceID;
}
}
public bool IsSelected
{
set
{
_IsSelected = value;
ItemSelectedEventArgs obj = new ItemSelectedEventArgs(_objTrinityEvent);
OnSelectedEvent(this, obj);
}
get
{
return _IsSelected;
}
}
}
public class ItemSelectedEventArgs : EventArgs
{
private ITrinityEvent _objItem;
public ItemSelectedEventArgs(ITrinityEvent objItem)
{
_objItem = objItem;
}
public ITrinityEvent SlectedNode
{
get
{
return _objItem;
}
}
}
public sealed class TrinityEventData : AbsTrinityEvent
{
public TrinityEventData(ITrinityEvent objEvent)
: base(objEvent)
{
}
}
I am binding this to my listview in code behind ( Not in XAML ) using following function
public void SetupColumnsForUnAcklist()
{
//Create Columns for listview
GridView grdView = new GridView();
grdView.Columns.Add(new GridViewColumn() { DisplayMemberBinding = new Binding() { Path = new PropertyPath("EventDescription") }, Header = "Description" });
grdView.Columns.Add(new GridViewColumn() { DisplayMemberBinding = new Binding() { Path = new PropertyPath("EventDateTime") }, Header = "Date:Time" });
grdView.Columns.Add(new GridViewColumn() { DisplayMemberBinding = new Binding() { Path = new PropertyPath("Site") }, Header = "Site" });
grdView.Columns.Add(new GridViewColumn() { DisplayMemberBinding = new Binding() { Path = new PropertyPath("DeviceName") }, Header = "Device" });
grdView.Columns.Add(new GridViewColumn() { DisplayMemberBinding = new Binding() { Path = new PropertyPath("Priority") }, Header = "Priority" });
lstview_Unack.View = grdView;
//Do Binding
if (_alarmUnAckList != null)
{
lstview_Unack.SetBinding(ListView.ItemsSourceProperty, new Binding() { Source = _alarmUnAckList });
lstview_Unack.SetBinding(ListView.IsSelectedProperty, new Binding() { Path = new PropertyPath("IsSelected") });
}
lstview_Unack.ContextMenu = contextMenu;
foreach (GridViewColumn col in grdView.Columns)
{
comboColumnList.Items.Add(col.Header as string);
}
}
My problem is, I want bind ListViewItem "IsSelected" Property to the TrinityEventData's "IsSelected" Property. How I should I do it in code behind?
First off, you're much better off doing this in XAML. It makes things much clearer and shorter. I'm going to answer in both XAML and code-behind to demonstrate this.
The easiest way is to make a Style applied to ListViewItem and using a Setter to apply the binding. On a ListViewItem, the DataContext is going to be your bound item (TrinityEventData in this case).
Assuming you had your ListView in XAML:
<ListView x:Name="lstview_Unack">
<ListView.Resources>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
</ListView.Resources>
</ListView>
In code, you have to construct the Style, Setter, and Binding by hand:
Style listViewItemStyle = new Style { TargetType = typeof(ListViewItem) };
listViewItemStyle.Setters.Add(new Setter
{
Property = ListViewItem.IsSelectedProperty,
Value = new Binding { Path = new PropertyPath("IsSelected") }
});
lstview_Unack.Resources.Add(typeof(ListViewItem), listViewItemStyle);
There are issues with this and virtualization, however. If your ListViewItems get virtualized, you might be unselecting items in the ListView but the binding won't be firing because your ListViewItem won't exist.
What worked for me is:
<ListView x:Name="lstview_Unack">
<ListView.ItemContainerStyle>
<Style TargetType="{x:Type ListViewItem}">
<Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}"/>
</Style>
</ListView.ItemContainerStyle>
</ListView>

Resources