I want to create ListBox and inside it should contained some elements.
My code:
<ListBox Name="listBoxQuestion" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{Binding Path=Tweets}" Background="Gray">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
In which way I cant put in ListBox my Grid and work on it ( I want have opportunity to transform it to star for example)
I have already tried:
<Grid Name="star1" MouseDown="close" Height="50" Width="50" RenderTransformOrigin="0.5,0" Grid.Column="0" Margin="20,0,0,0">
<DataGrid VerticalAlignment="Top" AutoGenerateColumns="False" ItemsSource="{Binding ElementName=listBox, Path=SelectedItem}"/>
</Grid>
XAML:
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="800" Width="800" Background="#FF143761">
<Grid Width="600" Margin="114,126,78,335">
<ListBox Name="listBoxQuestion" ScrollViewer.HorizontalScrollBarVisibility="Disabled" ItemsSource="{Binding ITEMS}">
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem">
<Setter Property="IsSelected" Value="{Binding Content.IsSelected, Mode=TwoWay, RelativeSource={RelativeSource Self}}"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListBoxItem">
<ContentPresenter/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
<ListBox.ItemTemplate>
<DataTemplate>
<Grid Width="{Binding WIDTH}">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<StackPanel Grid.Row="0" Orientation="Horizontal">
<Label Name="id"
Content="{Binding SURVEY_ID}"
Grid.Row="0"
Grid.Column="0"/>
<Label Name="question"
Content="{Binding SURVEY_QUESTION}"
Grid.Row="0"
Grid.Column="1" VerticalAlignment="Stretch" />
</StackPanel>
<StackPanel Grid.Row="2" Orientation="Horizontal">
<Polygon Name="star1" Points="{Binding POINTS}" Fill="{Binding FILL_COLOR}" Stroke="{Binding STROKE_COLOR}" Width="{Binding STAR_WIDTH}" Height="{Binding STAR_HEIGHT}" HorizontalAlignment="{Binding H_Alignment}" VerticalAlignment="{Binding V_Alignment}" MouseDown="clicked"/>
<Polygon Name="star2" Points="{Binding POINTS}" Fill="{Binding FILL_COLOR}" Stroke="{Binding STROKE_COLOR}" Width="{Binding STAR_WIDTH}" Height="{Binding STAR_HEIGHT}" HorizontalAlignment="{Binding H_Alignment}" VerticalAlignment="{Binding V_Alignment}" MouseDown="clicked"/>
<Polygon Name="star3" Points="{Binding POINTS}" Fill="{Binding FILL_COLOR}" Stroke="{Binding STROKE_COLOR}" Width="{Binding STAR_WIDTH}" Height="{Binding STAR_HEIGHT}" HorizontalAlignment="{Binding H_Alignment}" VerticalAlignment="{Binding V_Alignment}" MouseDown="clicked"/>
<Polygon Name="star4" Points="{Binding POINTS}" Fill="{Binding FILL_COLOR}" Stroke="{Binding STROKE_COLOR}" Width="{Binding STAR_WIDTH}" Height="{Binding STAR_HEIGHT}" HorizontalAlignment="{Binding H_Alignment}" VerticalAlignment="{Binding V_Alignment}" MouseDown="clicked"/>
<Polygon Name="star5" Points="{Binding POINTS}" Fill="{Binding FILL_COLOR}" Stroke="{Binding STROKE_COLOR}" Width="{Binding STAR_WIDTH}" Height="{Binding STAR_HEIGHT}" HorizontalAlignment="{Binding H_Alignment}" VerticalAlignment="{Binding V_Alignment}" MouseDown="clicked"/>
</StackPanel>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</Window>
CODE:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Drawing;
using System.Collections.ObjectModel;
using System.Text.RegularExpressions;
namespace WpfApplication1
{
public class Item
{
public uint width;
public uint starWidth;
public uint starHeight;
public string id;
public string question;
public PointCollection points;
public SolidColorBrush fillColor;
public SolidColorBrush strokeColor;
public HorizontalAlignment horizontalAlignment;
public VerticalAlignment verticalAlignment;
public uint WIDTH
{
get { return width; }
set { width = value; }
}
public uint STAR_WIDTH
{
get { return starWidth; }
set { starWidth = value; }
}
public uint STAR_HEIGHT
{
get { return starHeight; }
set { starHeight = value; }
}
public string SURVEY_ID
{
get { return id; }
set { id = value; }
}
public string SURVEY_QUESTION
{
get { return question; }
set { question = value; }
}
public PointCollection POINTS
{
get { return points; }
set { points = value; }
}
public SolidColorBrush FILL_COLOR
{
get { return fillColor; }
set { fillColor = value; }
}
public SolidColorBrush STROKE_COLOR
{
get { return strokeColor; }
set { strokeColor = value; }
}
public HorizontalAlignment H_Alignment
{
get { return horizontalAlignment; }
set { horizontalAlignment = value; }
}
public VerticalAlignment V_Alignment
{
get { return verticalAlignment; }
set { verticalAlignment = value; }
}
}
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
listBoxQuestion.ItemsSource = createItems();
}
private List<Item> createItems()
{
List<Item> items = new List<Item>();
items.Add(createItem("1)", "Question 1"));
items.Add(createItem("2)", "Question 2"));
items.Add(createItem("3)", "Question 3"));
return items;
}
private Item createItem(string id, string question)
{
Item item = new Item();
item.width = 800;
item.starHeight = 50;
item.starWidth = 50;
item.horizontalAlignment = HorizontalAlignment.Left;
item.verticalAlignment = VerticalAlignment.Center;
item.id = id;
item.question = question;
item.points = getPoints();
item.fillColor = getFillColor("Transparent");
item.strokeColor = getStrokeColor("Green");
return item;
}
private PointCollection getPoints()
{
PointCollection myPointLeftCollection = new PointCollection();
System.Drawing.PointF[] pts = new System.Drawing.PointF[5];
double rx = 24 / 2;
double ry = 24 / 2;
double cx = 0 + rx;
double cy = 0 + ry;
// Start at the top.
double theta = -Math.PI / 2;
double dtheta = 4 * Math.PI / 5;
for (int i = 0; i < 5; i++)
{
pts[i] = new System.Drawing.PointF(
(float)(cx + rx * Math.Cos(theta)),
(float)(cy + ry * Math.Sin(theta)));
theta += dtheta;
}
System.Windows.Point Point1Feedback = new System.Windows.Point(pts[0].X, pts[0].Y);
System.Windows.Point Point2Feedback = new System.Windows.Point(16, 8);
System.Windows.Point Point3Feedback = new System.Windows.Point(pts[3].X, pts[3].Y);
System.Windows.Point Point4Feedback = new System.Windows.Point(18, 14);
System.Windows.Point Point5Feedback = new System.Windows.Point(pts[1].X, pts[1].Y);
System.Windows.Point Point6Feedback = new System.Windows.Point(12, 18);
System.Windows.Point Point7Feedback = new System.Windows.Point(pts[4].X, pts[4].Y);
System.Windows.Point Point8Feedback = new System.Windows.Point(6, 14);
System.Windows.Point Point9Feedback = new System.Windows.Point(pts[2].X, pts[2].Y);
System.Windows.Point Point10Feedback = new System.Windows.Point(9, 8);
myPointLeftCollection.Add(Point1Feedback);
myPointLeftCollection.Add(Point2Feedback);
myPointLeftCollection.Add(Point3Feedback);
myPointLeftCollection.Add(Point4Feedback);
myPointLeftCollection.Add(Point5Feedback);
myPointLeftCollection.Add(Point6Feedback);
myPointLeftCollection.Add(Point7Feedback);
myPointLeftCollection.Add(Point8Feedback);
myPointLeftCollection.Add(Point9Feedback);
myPointLeftCollection.Add(Point10Feedback);
return myPointLeftCollection;
}
private SolidColorBrush getFillColor(string themeColorInner)
{
return (SolidColorBrush)new BrushConverter().ConvertFromString(themeColorInner);
}
private SolidColorBrush getStrokeColor(string themeColorBorder)
{
return (SolidColorBrush)new BrushConverter().ConvertFromString(themeColorBorder);
}
private void clicked(object sender, RoutedEventArgs e)
{
}
}
}
Related
First i tried this , but not sure where and how to implement it.
<ListView.Resources>
<ControlTemplate x:Key="SelectedTemplate" TargetType="ListViewItem">
<Border CornerRadius="5" BorderThickness="1" BorderBrush="DarkGray" Background="#FF92C6F9" Padding="2" HorizontalAlignment="Left" Margin="5" Tag="{Binding Value}" Cursor="Hand" MouseUp="Border_MouseUp_1">
<TextBlock Text="{Binding Name}" Margin="5" />
</Border>
</ControlTemplate>
<Style TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Border CornerRadius="5" BorderThickness="1" BorderBrush="DarkGray" Background="WhiteSmoke" Padding="2" HorizontalAlignment="Left" Margin="5" Tag="{Binding Value}" Cursor="Hand" MouseUp="Border_MouseUp_1" >
<TextBlock Text="{Binding Name}" Margin="5" />
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
<Style.Triggers>
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="true" />
<Condition Property="Selector.IsSelectionActive" Value="true" />
</MultiTrigger.Conditions>
<Setter Property="Template" Value="{StaticResource SelectedTemplate}" />
</MultiTrigger>
</Style.Triggers>
</Style>
</ListView.Resources>
i tried after the listview name or inside the grid part but got too many errors.
this is my xaml code
<Window x:Class="Lab_ListView.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:Lab_ListView"
mc:Ignorable="d"
Title="Video Game List" Height="450" Width="800">
<Grid Margin="0,0,10,10">
<Label Content="Game Name" HorizontalAlignment="Left" Margin="40,59,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="GameNameTextBox" HorizontalAlignment="Left" Height="23" Margin="121,62,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="366"/>
<Button x:Name="AddBtn" Content="Add" HorizontalAlignment="Left" Margin="121,151,0,0" VerticalAlignment="Top" Width="75" Click="AddBtn_Click"/>
<ListView x:Name="VideoGameListView" HorizontalAlignment="Left" Height="166" Margin="40,203,0,0" VerticalAlignment="Top" Width="447">
<ListView.View>
<GridView>
<GridViewColumn Header="Game Name" DisplayMemberBinding="{Binding GameName}"/>
<GridViewColumn Header="Rating" DisplayMemberBinding="{Binding Rating}"/>
<GridViewColumn Header="Price" DisplayMemberBinding="{Binding Price}"/>
</GridView>
</ListView.View>
</ListView>
<Label Content="Rating" HorizontalAlignment="Left" Margin="40,90,0,0" VerticalAlignment="Top"/>
<Label Content="Price" HorizontalAlignment="Left" Margin="40,121,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="PriceTextBox" HorizontalAlignment="Left" Height="23" Margin="121,123,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="366"/>
<TextBox x:Name="RatingTextBox" HorizontalAlignment="Left" Height="23" Margin="121,92,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="366"/>
</Grid>
</Window>
this is the code of the class Cropped_Info
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Lab_ListView
{
class Cropped_Info
{
private string m_GameName;
private string m_Rating;
private double m_Price;
public string GameName
{
get
{
return m_GameName;
}
set
{
m_GameName = value;
}
}
public string Rating
{
get
{
return m_Rating;
}
set
{
m_Rating = value;
}
}
public double Price
{
get
{
return m_Price;
}
set
{
m_Price = value;
}
}
public Cropped_Info()
{
GameName = " ";
Rating = " ";
Price = 0.0;
}
}
}
and the main xaml.cs code where i'm adding the items to the listView
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Lab_ListView
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
Cropped_Info vg = new Cropped_Info();
int counter = 0;
Random random;
List<Cropped_Info> list = new List<Cropped_Info>();
System.Windows.Threading.DispatcherTimer dispatcherTimer;
public MainWindow()
{
InitializeComponent();
random= new Random();
this.WindowStartupLocation = WindowStartupLocation.CenterScreen;
dispatcherTimer = new System.Windows.Threading.DispatcherTimer();
dispatcherTimer.Tick += DispatcherTimer_Tick;
dispatcherTimer.Interval = new TimeSpan(0, 0, 0);
dispatcherTimer.Start();
}
private void DispatcherTimer_Tick(object sender, EventArgs e)
{
vg = new Cropped_Info();
vg.GameName = randStr(5) + " " + counter.ToString();
VideoGameListView.Items.Add(vg);
if(counter == 1000)
{
dispatcherTimer.Stop();
for(int i = 0; i < VideoGameListView.Items.Count; i++)
{
var tt = VideoGameListView.Items[i];
}
}
counter++;
}
public string randStr(int len)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789!##$%^&*()";
return new string(Enumerable.Repeat(chars, len).Select(s => s[random.Next(s.Length)]).ToArray());
}
}
}
i want that each string item that is added to the listView to be colored in some color can be random color but the main goal is to color each item.
You can use a converter to achieve that. For example, the color's Red channel might depend on the Price. The greater the Price, the more red the color could be, like this:
Here's an example of how that could be done:
MainWindow.xaml
<Window
x:Class="WpfListViewColorsDemo.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:WpfListViewColorsDemo"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Window.Resources>
<local:PriceToBackgroundColorConverter x:Key="PriceToBackgroundColorConverter" />
</Window.Resources>
<Grid>
<ListView x:Name="ListViewItems">
<ListView.ItemTemplate>
<DataTemplate>
<!-- The Background="{Binding Price, Converter={StaticResource PriceToBackgroundColorConverter}}" is where Price gets converted into a Brush that can be set as the Background -->
<Border
Padding="5"
Background="{Binding Price, Converter={StaticResource PriceToBackgroundColorConverter}}"
BorderThickness="1"
CornerRadius="5">
<TextBlock Foreground="White">
<Run Text="{Binding Name}" />
<Run Text="{Binding Price, StringFormat=c}" />
</TextBlock>
</Border>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
MainWindow.xaml.cs, Item.cs and PriceToBackgroundColorConverter.cs
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Windows;
using System.Windows.Data;
using System.Windows.Media;
namespace WpfListViewColorsDemo;
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
ListViewItems.ItemsSource = new List<Item>
{
new Item()
{
Name = "Apple",
Price = 15.99
},
new Item()
{
Name = "Peach",
Price = 24.50
},
new Item()
{
Name = "Watermelon",
Price = 39.66
},
new Item()
{
Name = "Diamond",
Price = 70.42
},
new Item()
{
Name = "Unicorn",
Price = 99.00
}
};
}
}
public class Item
{
public string? Name { get; set; }
public double Price { get; set; }
}
public class PriceToBackgroundColorConverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
if(value is double price)
{
return ConvertPriceToColor(price);
}
return value;
}
private Brush ConvertPriceToColor(double price)
{
// Add your custom coloring logic here.
// I'm simply making the color more red as the price goes up (capped at 100).
var red = Clamp(price, 0, 100) * 255 / 100;
var color = Color.FromArgb(255, (byte)red, 0, b: 0);
return new SolidColorBrush(color);
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
//do nothing here
return value;
}
private double Clamp(double value, double min, double max)
{
if(min > max)
{
throw new ArgumentOutOfRangeException();
}
if(value < min)
{
return min;
}
if(value > max)
{
return max;
}
return value;
}
}
I have a chart inside a user control (Chart UC), which is just like the LiveCharts zooming and panning example, so the Chart UC has bindings to it's code behind. I have an other user control (let's call it Item UC), which contains 2 Chart UCs. The Item UC has bindings and commands, all of which works with its view model (Item VM). What I haven't been able to figure out, how to set up the connection between the Chart UCs' Series property and the Item VM.
The Chart UC xaml:
<UserControl x:Class="responsive_ui_test.User_Controls.ZoomingAndPanning"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:responsive_ui_test.User_Controls"
xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
xmlns:zoomingAndPanning="clr-namespace:responsive_ui_test.User_Controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<zoomingAndPanning:ZoomingModeCoverter x:Key="ZoomingModeCoverter"></zoomingAndPanning:ZoomingModeCoverter>
</UserControl.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<lvc:CartesianChart Series="{Binding Series}" Zoom="{Binding ZoomingMode}" >
<lvc:CartesianChart.AxisX>
<lvc:Axis Name="X" Title="{Binding XAxisTitle}" LabelFormatter="{Binding XFormatter}"
Separator="{x:Static lvc:DefaultAxes.CleanSeparator}"/>
</lvc:CartesianChart.AxisX>
<lvc:CartesianChart.AxisY>
<lvc:Axis Name="Y" Title="{Binding YAxisTitle}" LabelFormatter="{Binding YFormatter}"/>
</lvc:CartesianChart.AxisY>
</lvc:CartesianChart>
<Button Grid.Row="1" Click="ResetZoomOnClick" Background="#FFDDDDDD">Reset Zoom</Button>
</Grid>
</UserControl>
Chart UC code behind:
namespace responsive_ui_test.User_Controls
{
public partial class ZoomingAndPanning : INotifyPropertyChanged
{
private ZoomingOptions _zoomingMode;
public ZoomingAndPanning()
{
InitializeComponent();
var gradientBrush = new LinearGradientBrush
{
StartPoint = new Point(0, 0),
EndPoint = new Point(0, 1)
};
gradientBrush.GradientStops.Add(new GradientStop(Color.FromRgb(33, 148, 241), 0));
gradientBrush.GradientStops.Add(new GradientStop(Colors.Transparent, 1));
ZoomingMode = ZoomingOptions.X;
DataContext = this;
}
public SeriesCollection Series { get; set; }
public Func<double, string> XFormatter { get; set; }
public Func<double, string> YFormatter { get; set; }
public string XAxisTitle { get; set; }
public string YAxisTitle { get; set; }
public ZoomingOptions ZoomingMode
{
get { return _zoomingMode; }
set
{
_zoomingMode = value;
OnPropertyChanged();
}
}
private void ToogleZoomingMode(object sender, RoutedEventArgs e)
{
switch (ZoomingMode)
{
case ZoomingOptions.None:
ZoomingMode = ZoomingOptions.X;
break;
case ZoomingOptions.X:
ZoomingMode = ZoomingOptions.Y;
break;
case ZoomingOptions.Y:
ZoomingMode = ZoomingOptions.Xy;
break;
case ZoomingOptions.Xy:
ZoomingMode = ZoomingOptions.None;
break;
default:
throw new ArgumentOutOfRangeException();
}
}
private ChartValues<ObservablePoint> GetData()
{
var r = new Random();
var min = 0;
var max = 65535;
var values = new ChartValues<ObservablePoint>();
for (var i = 1; i < 100; i++)
{
var seed = r.NextDouble();
var value = seed * (max - min) + min;
values.Add(new ObservablePoint(i, value));
}
return values;
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged(string propertyName = null)
{
if (PropertyChanged != null) PropertyChanged.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void ResetZoomOnClick(object sender, RoutedEventArgs e)
{
//Use the axis MinValue/MaxValue properties to specify the values to display.
//use double.Nan to clear it.
X.MinValue = double.NaN;
X.MaxValue = double.NaN;
Y.MinValue = double.NaN;
Y.MaxValue = double.NaN;
}
}
public class ZoomingModeCoverter : IValueConverter
{
public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
{
switch ((ZoomingOptions)value)
{
case ZoomingOptions.None:
return "None";
case ZoomingOptions.X:
return "X";
case ZoomingOptions.Y:
return "Y";
case ZoomingOptions.Xy:
return "XY";
default:
throw new ArgumentOutOfRangeException();
}
}
public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
{
throw new NotImplementedException();
}
}
}
Item UC xaml:
<UserControl x:Class="responsive_ui_test.User_Controls.DeviceTab"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:responsive_ui_test.User_Controls"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
xmlns:uc="clr-namespace:responsive_ui_test.User_Controls">
<Grid>
<Grid Margin="10">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" MinWidth="250"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="2*" MinWidth="250"/>
</Grid.ColumnDefinitions>
<Grid Margin="0,0,5,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" MinHeight="80" MaxHeight="100"/>
<RowDefinition Height="*" MinHeight="80" MaxHeight="100"/>
<RowDefinition Height="3*"/>
</Grid.RowDefinitions>
<GroupBox Header="Port" Margin="0,0,0,10">
<Grid Margin="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<ComboBox ItemsSource="{Binding FoundDevices}" Margin="0,0,0,4"></ComboBox>
<Grid Grid.Row="1" Margin="0,4,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Command="{Binding ConnectCommand}" Margin="0,0,4,0">
Connect
<Button.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="10"/>
</Style>
</Button.Resources>
</Button>
<Button Command="{Binding ScanCommand}" Grid.Column="1" Margin="4,0,0,0">
Scan
<Button.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="10"/>
</Style>
</Button.Resources>
</Button>
</Grid>
</Grid>
</GroupBox>
<GroupBox Grid.Row="1" Header="Log File" Margin="0,0,0,10">
<Grid Margin="2">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<TextBox Text="{Binding FilePath}" IsReadOnly="True" Margin="0,0,0,4"/>
<Button Command="{Binding ChangeFilePathCommand}" Grid.Row="1" Margin="0,4,0,0">
Change
<Button.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="10"/>
</Style>
</Button.Resources>
</Button>
</Grid>
</GroupBox>
<GroupBox Grid.Row="2" Header="Temperature">
<uc:ZoomingAndPanning x:Name="lvcTemp"></uc:ZoomingAndPanning>
</GroupBox>
</Grid>
<GridSplitter Grid.Column="1" Width="5" HorizontalAlignment="Stretch" />
<Grid Grid.Column="2" Margin="5,0,0,0">
<Grid.RowDefinitions>
<RowDefinition Height="*" MinHeight="30" MaxHeight="30"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Button Command="{Binding CloseTabCommand}" Name="btnClose" Margin="0" Width="100" HorizontalAlignment="Right" Background="Red" FontWeight="Bold">
CLOSE TAB
<Button.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="10"/>
</Style>
</Button.Resources>
</Button>
<Button Command="{Binding NewTabCommand}" Name="btnNew" Margin="0,0,110,0" Width="100" HorizontalAlignment="Right" Background="LawnGreen" FontWeight="Bold">
NEW TAB
<Button.Resources>
<Style TargetType="Border">
<Setter Property="CornerRadius" Value="10"/>
</Style>
</Button.Resources>
</Button>
<GroupBox Grid.Row="1" Header="Measurement">
<uc:ZoomingAndPanning Grid.Row="1" x:Name="lvcMeas"></uc:ZoomingAndPanning>
</GroupBox>
</Grid>
</Grid>
</Grid>
</UserControl>
Item UC's view model:
namespace responsive_ui_test.View_Models
{
class DeviceViewModel : ViewModelBase
{
int count = 0;
private readonly DelegateCommand _scanCommand;
private readonly DelegateCommand _connectCommand;
private readonly DelegateCommand _changeFilePathCommand;
private readonly DelegateCommand _closeTabCommand;
private readonly DelegateCommand _newTabCommand;
public ICommand ScanCommand => _scanCommand;
public ICommand ConnectCommand => _connectCommand;
public ICommand ChangeFilePathCommand => _changeFilePathCommand;
public ICommand CloseTabCommand => _closeTabCommand;
public ICommand NewTabCommand => _newTabCommand;
public DeviceViewModel()
{
_scanCommand = new DelegateCommand(OnScan);
_connectCommand = new DelegateCommand(OnConnect);
_changeFilePathCommand = new DelegateCommand(OnChangeFilePath);
_closeTabCommand = new DelegateCommand(OnCloseTab);
_newTabCommand = new DelegateCommand(OnNewTab);
_tabName = "Unconnected";
}
private string _filePath;
public string FilePath
{
get => _filePath;
set => SetProperty(ref _filePath, value);
}
private ObservableCollection<string> _foundDevices;
public ObservableCollection<string> FoundDevices
{
get => _foundDevices;
set => SetProperty(ref _foundDevices, value);
}
private string _tabName;
public string TabName
{
get => _tabName;
set => SetProperty(ref _tabName, value);
}
private void OnScan(object commandParameter)
{
FilePath = "scan command " + count.ToString();
count++;
}
private void OnConnect(object commandParameter)
{
FilePath = "connect command " + count.ToString();
count++;
}
private void OnChangeFilePath(object commandParameter)
{
FilePath = "change file path command " + count.ToString();
count++;
}
private void OnCloseTab(object commandParameter)
{
FilePath = "close tab command " + count.ToString();
count++;
}
private void OnNewTab(object commandParameter)
{
FilePath = "new tab command " + count.ToString();
count++;
}
private ChartValues<ObservablePoint> GetData()
{
var r = new Random();
var min = 0;
var max = 65535;
var values = new ChartValues<ObservablePoint>();
for (var i = 1; i < 50; i++)
{
var seed = r.NextDouble();
var value = seed * (max - min) + min;
values.Add(new ObservablePoint(i, value));
}
return values;
}
}
}
Main window xaml:
<Window x:Class="responsive_ui_test.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:uc="clr-namespace:responsive_ui_test.User_Controls"
xmlns:local="clr-namespace:responsive_ui_test"
mc:Ignorable="d"
Title="App" Height="550" Width="800" MinWidth="800" MinHeight="550">
<Grid>
<Grid.Resources>
<DataTemplate x:Key="CustomHeaderTemplate">
<DockPanel LastChildFill="True">
<!--<Button Content="X" DockPanel.Dock="Right">
<Button.Template>
<ControlTemplate>
<Label FontWeight="Bold" Content="X" />
</ControlTemplate>
</Button.Template>
</Button>-->
<Label Content="{Binding TabName}" />
</DockPanel>
</DataTemplate>
</Grid.Resources>
<TabControl x:Name="tbCtrl" ItemsSource="{Binding Items}" Loaded="tbCtrl_Loaded" SelectionChanged="tbCtrl_SelectionChanged" ItemTemplate="{StaticResource CustomHeaderTemplate}">
<TabControl.ContentTemplate>
<DataTemplate>
<uc:DeviceTab/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Grid>
</Window>
Main window code behind:
namespace responsive_ui_test
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
private ChartValues<ObservablePoint> GetData()
{
var r = new Random();
var min = 0;
var max = 65535;
var values = new ChartValues<ObservablePoint>();
for (var i = 1; i < 50; i++)
{
var seed = r.NextDouble();
var value = seed * (max - min) + min;
values.Add(new ObservablePoint(i, value));
}
return values;
}
private void tbCtrl_Loaded(object sender, RoutedEventArgs e)
{
var tabControlViewModel = new TabControlViewModel();
tabControlViewModel.Items.Add(new DeviceViewModel()
{
FilePath = "C:/1/",
FoundDevices = new ObservableCollection<string>()
{
"1", "2"
},
});
DataContext = tabControlViewModel;
tbCtrl.SelectedIndex = 0;
}
private void tbCtrl_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if (tbCtrl.SelectedIndex < 0) // if selection is empty
return;
var cnt = tbCtrl.Items.Count;
Debug.WriteLine("Item count: " + cnt);
Debug.WriteLine("Selected Index: " + tbCtrl.SelectedIndex);
}
}
}
Tab contorl's view model:
namespace responsive_ui_test.View_Models
{
class TabControlViewModel : ViewModelBase
{
public ObservableCollection<DeviceViewModel> Items { get; } = new ObservableCollection<DeviceViewModel>();
}
}
What I need to have inside the DeviceViewModel is a chart SeriesCollection property for each chart inside the Item UC. It's just not clear to me how to get this connection in my situation. I've spent a lot of time trying around and evetything works except the charts. I appreciate any help a lot, thank you so much in advance!
Finally I found a solution. I just created 2 different LiveCharts user controls which are the same, but the Binding for the chart's SeriesCollection is named differently. This way, I can bind to both chart's SeriesCollection from the view model and it works great.
Here is my goal (simplified) : Create a userControl to display readable bitField.
Exemple with value 0x3: want to display option1 (bit 1): enable, option2 (bit 2):enable, option3 (bit 3): disable ...
userControl behavior: if I click on this control, it's open a popup (like combobox) with checkBoxes which allow you to enable optionX (which will change the value and displayed text).
This is the source code I use for the UserControl view
<UserControl x:Name="userControl" x:Class="MyProg.Views.BitField"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:MyProg.Views"
mc:Ignorable="d"
>
<Grid x:Name="LayoutRoot" Height="{Binding ActualHeight, ElementName=userControl, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Width="{Binding ActualWidth, ElementName=userControl, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<ToggleButton x:Name="TogglePopupButton" Background="Transparent" BorderBrush="Transparent" HorizontalContentAlignment="Stretch" VerticalContentAlignment="Stretch" >
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="auto" />
</Grid.ColumnDefinitions>
<Label Content="{Binding Path=Text}" Grid.Column="0" VerticalAlignment="Center" Margin="0,-5,0,-5" />
<Path x:Name="Arrow" Grid.Column="1" Fill="Black" VerticalAlignment="Center" Data="M0,0 L0,2 L4,6 L8,2 L8,0 L4,4 z" HorizontalAlignment="Right"/>
</Grid>
</ToggleButton>
<Popup x:Name="ToggledPopup" StaysOpen="False" IsOpen="{Binding IsChecked, ElementName=TogglePopupButton, Mode=TwoWay}" Width="{Binding ActualWidth, ElementName=userControl, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" Grid.Row="1">
<Border Background="White" BorderThickness="1" BorderBrush="Black">
<ScrollViewer HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="5"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<CheckBox Content="option 1" Grid.Column="0" />
<CheckBox Content="option 2" Grid.Column="2" />
<CheckBox Content="option 3" Grid.Column="4" />
</Grid>
</ScrollViewer>
</Border>
</Popup>
</Grid>
</UserControl>
The code behind for binding value
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using MyProg.ViewModels;
namespace MyProg.Views
{
/// <summary>
/// Interaction logic for BitField.xaml
/// </summary>
public partial class BitField : UserControl
{
internal vmBitField m_ViewModel;
public BitField()
{
InitializeComponent();
// Load the viewModel
m_ViewModel = new vmBitField();
LayoutRoot.DataContext = m_ViewModel;
m_ViewModel.PropertyChanged += M_ViewModel_PropertyChanged;
}
private void M_ViewModel_PropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == "Value")
{
if(IntValue != m_ViewModel?.Value)
IntValue = (int)m_ViewModel.Value;
}
}
/// <summary>
/// Gets or sets the value which is displayed
/// </summary>
public int IntValue
{
get { return (int)GetValue(ValueProperty); }
set { SetValue(ValueProperty, value);}
}
/// <summary>
/// Identified the Value dependency property
/// </summary>
public static readonly DependencyProperty ValueProperty = DependencyProperty.Register("IntValue", typeof(int), typeof(BitField), new PropertyMetadata(0, OnIntValueSet));
private static void OnIntValueSet(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
((BitField)d).m_ViewModel.Value = (uint?)(int)e.NewValue;
}
}
}
and the UserControl viewModel
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MyProg.MVVM;
namespace MyProg.ViewModels
{
class vmBitField : ViewModelBase
{
#region Members
protected uint m_Value = 0; // 7
#endregion
#region Properties
public uint? Value { get { return m_Value; } set { if (value != m_Value) { m_Value = (uint)value; RaiseEventPropertyChanged("Option1"); RaiseEventPropertyChanged("Option2"); RaiseEventPropertyChanged("Option3"); RaiseEventPropertyChanged("Text"); } } }
public bool Option1 { get {return (Value & 0x1) == 1; } set { if (value != Option1) { m_Value ^= 0x1; RaiseEventPropertyChanged("Option1"); RaiseEventPropertyChanged("Value"); RaiseEventPropertyChanged("Text"); } } }
public bool Option2 { get { return (Value & 0x2) == 1; } set { if (value != Option2) { m_Value ^= 0x2; RaiseEventPropertyChanged("Option2"); RaiseEventPropertyChanged("Value"); RaiseEventPropertyChanged("Text"); } } }
public bool Option3 { get { return (Value & 0x4) == 1; } set { if (value != Option3) { m_Value ^= 0x4; RaiseEventPropertyChanged("Option3"); RaiseEventPropertyChanged("Value"); RaiseEventPropertyChanged("Text"); } } }
public string Text { get { return "Option1:" + Option1 + " Option2:" + Option2 + " Option3:" + Option3; } }
#endregion
#region Contructors
public vmBitField()
{
}
#endregion
#region Methodes
#endregion
}
}
This works correctly when I insert this userControl in a page or windows.
<local:LockType IntValue="{Binding Path=ValueAsInt, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
Now, I have a list with lot of bitfield. I want to display all of this in a datagrid. So I want to insert this userControl in a dataGrid.
This is the code to add the datagrid
<DataGrid Grid.Row="13" Grid.ColumnSpan="3" AutoGenerateColumns="False" Name="dataGrid1" AlternationCount="2"
ItemsSource="{Binding Values}"
CanUserAddRows="False" CanUserDeleteRows="False" CanUserResizeRows="False" CanUserReorderColumns="False" >
<DataGrid.Columns>
<DataGridTemplateColumn Header="Id" HeaderStyle="{StaticResource DataGridHeaderCenter}"
CellTemplate="{StaticResource IdText}"/>
<DataGridTemplateColumn Header="Value" Width="400" HeaderStyle="{StaticResource DataGridHeaderCenter}" >
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<local1:LockType IntValue="{Binding Path=ValueAsInt, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
<DataGridTemplateColumn Header="CurrentValue"
CellTemplate="{StaticResource CurrentValueText}" />
</DataGrid.Columns>
</DataGrid>
When my usercontrol is in a datagrid, when I click on togglebuton, it's open the popup correctly, but then I can't interact (check or uncheck) with any of checkBoxes inside the popup.
Anyone could help me to find why checkboxes inside a popup doesn't fired event ?
I could add more info if needed.
Best Regards
JM
You will have to set the FocusManager.IsFocusScope of the popup to true.
You can also set the cell's IsFocussable property through a style setter.
<Style TargetType="{x:Type DataGridCell}"> <Setter Property="Focusable" Value="False"></Setter> </Style>
The problem why it does not let you edit anything on the popup is because the cell editing has not ended. Hence, you can also do the following by registering to the DataGrid_CellEditEnding event.
private static void DataGrid_CellEditEnding(object sender, DataGridCellEditEndingEventArgs e)
{
if (e.Column.GetType() == typeof(DataGridTemplateColumn))
{
var popup = GetVisualChild<Popup>(e.EditingElement);
if (popup != null && popup.IsOpen)
{
e.Cancel = true;
}
}
}
I just wanted to start off saying I've seen similar posts with the same issue but they give a solution not suitable to my scenario. I'm making a SplitView Control as shown below. Problem is the Control has 3 areas where users can place whatever controls they want, but those controls can't be named via this error:
Cannot set Name attribute value 'Item1' on element 'ListViewItem'. 'ListViewItem' is under the scope of element 'SplitView', which already had a name registered when it was defined in another scope.
How can I fix this? I don't want the implementation of this control to have to always have to add some code to get around this error. Could I add a 3 template areas in this control so the user can make a their own template with content they want inside each area. How would I do this? I'm open to other ideas.
Markup
<UserControl x:Name="ThisControl" x:Class="ns.SplitView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d" DataContext="{Binding RelativeSource={RelativeSource Self}}"
d:DesignHeight="300" d:DesignWidth="300">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Button Margin="10" Grid.Row="0" Grid.Column="0" x:Name="OpenPaneButton" Width="50" Height="50" Click="OpenPaneButton_Click" Background="{x:Null}" BorderBrush="{x:Null}" Focusable="False" >
<Viewbox>
<Canvas Width="300" Height="210">
<Path StrokeThickness="1" StrokeDashArray="" StrokeDashCap="Flat" StrokeDashOffset="0" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat" StrokeLineJoin="Miter" StrokeMiterLimit="10" Stroke="{Binding HamburgerButtonColor, ElementName=ThisControl}" Fill="{Binding HamburgerButtonColor, ElementName=ThisControl}">
<Path.Data>
<RectangleGeometry Rect="0,0,300,50" RadiusX="25" RadiusY="25" />
</Path.Data>
</Path>
<Path StrokeThickness="1" StrokeDashArray="" StrokeDashCap="Flat" StrokeDashOffset="0" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat" StrokeLineJoin="Miter" StrokeMiterLimit="10" Stroke="{Binding HamburgerButtonColor, ElementName=ThisControl}" Fill="{Binding HamburgerButtonColor, ElementName=ThisControl}">
<Path.Data>
<RectangleGeometry Rect="0,80,300,50" RadiusX="25" RadiusY="25" />
</Path.Data>
</Path>
<Path StrokeThickness="1" StrokeDashArray="" StrokeDashCap="Flat" StrokeDashOffset="0" StrokeStartLineCap="Flat" StrokeEndLineCap="Flat" StrokeLineJoin="Miter" StrokeMiterLimit="10" Stroke="{Binding HamburgerButtonColor, ElementName=ThisControl}" Fill="{Binding HamburgerButtonColor, ElementName=ThisControl}">
<Path.Data>
<RectangleGeometry Rect="0,160,300,50" RadiusX="25" RadiusY="25" />
</Path.Data>
</Path>
</Canvas>
</Viewbox>
</Button>
<ContentPresenter x:Name="MainTitleContent" Panel.ZIndex="1" Content="{Binding TitleContent, ElementName=ThisControl}" Grid.Row="0" Grid.Column="1" Focusable="True"/>
<ContentPresenter x:Name="Pane" Panel.ZIndex="1" Grid.ColumnSpan="2" Grid.Column="0" Grid.Row="0" Grid.RowSpan="2" Width="0" HorizontalAlignment="Left" Content="{Binding PaneContent, ElementName=ThisControl}" LostFocus="Pane_LostFocus" LostMouseCapture="Pane_LostMouseCapture" LostKeyboardFocus="Pane_LostKeyboardFocus" LostTouchCapture="Pane_LostTouchCapture" LostStylusCapture="Pane_LostStylusCapture" Focusable="True"/>
<ContentPresenter x:Name="Content" Grid.ColumnSpan="2" Grid.Column="0" Grid.Row="1" Content="{Binding MainContent, ElementName=ThisControl}" Focusable="True"/>
</Grid>
</UserControl>
Code Behind
using System;
using System.Windows;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
namespace ns
{
public partial class SplitView
{
/// <summary>
/// A simple state to know if the pane is open
/// </summary>
public bool PaneIsOpen
{
get { return (bool)GetValue(PaneIsOpenProperty); }
set { SetValue(PaneIsOpenProperty, value); }
}
public static readonly DependencyProperty PaneIsOpenProperty = DependencyProperty.Register("PaneIsOpen", typeof(bool), typeof(SplitView));
public SolidColorBrush HamburgerButtonColor
{
get { return (SolidColorBrush)GetValue(HamburgerButtonColorProperty); }
set { SetValue(HamburgerButtonColorProperty, value); }
}
public static readonly DependencyProperty HamburgerButtonColorProperty = DependencyProperty.Register("HamburgerButtonColor", typeof(SolidColorBrush), typeof(SplitView), new UIPropertyMetadata(new SolidColorBrush(Colors.Black)));
public double PaneWidth
{
get { return (double)GetValue(PaneWidthProperty); }
set { SetValue(PaneWidthProperty, value); }
}
public static readonly DependencyProperty PaneWidthProperty = DependencyProperty.Register("PaneWidth", typeof(double), typeof(SplitView), new PropertyMetadata(null));
public object MainContent
{
get { return GetValue(MainContentProperty); }
set { SetValue(MainContentProperty, value); }
}
public static readonly DependencyProperty MainContentProperty = DependencyProperty.Register("MainContent", typeof(object), typeof(SplitView), new PropertyMetadata(null));
public object PaneContent
{
get { return GetValue(PaneContentProperty); }
set { SetValue(PaneContentProperty, value); }
}
public static readonly DependencyProperty PaneContentProperty = DependencyProperty.Register("PaneContent", typeof(object), typeof(SplitView), new PropertyMetadata(null));
public object TitleContent
{
get { return GetValue(TitleContentProperty); }
set { SetValue(TitleContentProperty, value); }
}
public static readonly DependencyProperty TitleContentProperty = DependencyProperty.Register("TitleContent", typeof(object), typeof(SplitView), new PropertyMetadata(null));
private readonly Duration PaneAnimationDuration = new Duration(new TimeSpan());
private DoubleAnimation ClosePaneAnimation => new DoubleAnimation {Duration = PaneAnimationDuration, To = 0, From = PaneWidth };
private DoubleAnimation OpenPaneAnimation => new DoubleAnimation {Duration = PaneAnimationDuration, To = PaneWidth, From = 0 };
public SplitView()
{
InitializeComponent();
}
private void OpenPaneButton_Click(object sender, RoutedEventArgs e)
{
PaneIsOpen = !PaneIsOpen;
//Debug.WriteLine($"pane is open: {PaneIsOpen}");
if (PaneIsOpen)
{
Pane.BeginAnimation(WidthProperty, OpenPaneAnimation);
Pane.Focus();
}
else
{
Pane.BeginAnimation(WidthProperty, ClosePaneAnimation);
}
}
private void Pane_LostFocus(object sender, RoutedEventArgs e)
{
PaneLostFocus();
e.Handled = true;
}
private void Pane_LostMouseCapture(object sender, MouseEventArgs e)
{
PaneLostFocus();
e.Handled = true;
}
private void PaneLostFocus()
{
if (PaneIsOpen)
{
PaneIsOpen = false;
Pane.BeginAnimation(WidthProperty, ClosePaneAnimation);
}
}
private void Pane_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
{
PaneLostFocus();
e.Handled = true;
}
private void Pane_LostTouchCapture(object sender, TouchEventArgs e)
{
PaneLostFocus();
e.Handled = true;
}
private void Pane_LostStylusCapture(object sender, StylusEventArgs e)
{
PaneLostFocus();
e.Handled = true;
}
}
}
Implementation
<customControls:SplitView x:Name="SplitView" PaneWidth="250" HamburgerButtonColor="{StaticResource AccentColorBrush2}">
<customControls:SplitView.MainContent>
<Grid>
</Grid>
</customControls:SplitView.MainContent>
<customControls:SplitView.PaneContent>
<Grid Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="Navigation" Style="{StaticResource Header1}" Margin="10,5,5,5"/>
<!-- I can't name controls in these content areas -->
<ListView Grid.Row="1" BorderThickness="0" SelectionChanged="PaneItemsListView_SelectionChanged">
<ListViewItem x:Name="Item1" Style="{StaticResource SplitViewItemsStyle}" ">
<TextBlock Text="Project Explorer" Margin="20,5,10,5"/>
</ListViewItem>
<ListViewItem Style="{StaticResource SplitViewItemsStyle}" Tag="FieldServicesItem">
<TextBlock Text="Field Services" Margin="20,5,10,5"/>
</ListViewItem>
<ListViewItem Style="{StaticResource SplitViewItemsStyle}" Tag="ReportManagerItem">
<TextBlock Text="Report Manager" Margin="20,5,10,5"/>
</ListViewItem>
</ListView>
</Grid>
</customControls:SplitView.PaneContent>
<customControls:SplitView.TitleContent>
<Grid>
<TextBlock HorizontalAlignment="Center" Text="Current View" VerticalAlignment="Center" Style="{StaticResource Header1}"/>
</Grid>
</customControls:SplitView.TitleContent>
</customControls:SplitView>
So in my application I have to types of class objects, Circles and Rectangles. Both which got plotted using a ListBox. The rectangles are green and the circles are the yellow shapes.
You may be asking why am i using the listbox to display them. The benefit here is the freebie of making it possible for users to select the items when the click within the window as seen here.
The problems which i need help on, they all relate to the same topic which is clicking/selection.
Updated: 1/7/2016
Since all listbox items are displayed with a Box Shaped hit test area, it makes problems like this happen. A user wants to select the Rectangle but they get the Yellow Circle instead.
The Problem (Left)| The Desired Goal (Right)
This leads to my last problem which is the hit test for the Yellow Circle shapes. When a user clicks in a negative area it shouldn't actually select the line. It should only select the line when the users cursor is directly over it. as seen in the image on the right. It would be ideal that when it's selected, the highlight indication fits more around the shapes which is highlighted, rather than a huge rectangle.
As far as the code, its rather short, and i combined it for simplicity into lesser files.
MainWindow.xaml
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:WpfApplication1"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525"
Background="Gray">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type local:RectangleViewModel}" >
<Border Cursor="Hand" Background="Green" CornerRadius="4" Width="100" Height="100" Margin="10"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:CircleViewModel}" >
<Path Data="M0,0 C0,0 10,100 100,100" Stroke="Gold" StrokeThickness="5" Cursor="Hand"/>
</DataTemplate>
</Window.Resources>
<!-- Presents the Rectangles -->
<ListBox x:Name="listBox" ItemsSource="{Binding Items}" SelectionMode="Extended" Background="Transparent">
<ListBox.ItemsPanel>
<ItemsPanelTemplate>
<Canvas />
</ItemsPanelTemplate>
</ListBox.ItemsPanel>
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem" >
<Setter Property="Canvas.Left" Value="{Binding X}" />
<Setter Property="Canvas.Top" Value="{Binding Y}" />
</Style>
</ListBox.ItemContainerStyle>
<ListBox.Resources>
<Style TargetType="{x:Type ListBoxItem}">
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
</Style>
</ListBox.Resources>
</ListBox>
</Window>
MainWindowViewModel.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace WpfApplication1
{
public class MainWindowViewModel
{
private ObservableCollection<ItemViewModel> items = new ObservableCollection<ItemViewModel>();
public ObservableCollection<ItemViewModel> Items { get { return items; } }
public MainWindowViewModel()
{
// Populate the view model with some example data.
items.Add(new RectangleViewModel(250, 200));
items.Add(new RectangleViewModel(320, 370));
items.Add(new RectangleViewModel(100, 50));
items.Add(new RectangleViewModel(350, 25));
items.Add(new RectangleViewModel(70, 270));
items.Add(new CircleViewModel(20, 20));
items.Add(new CircleViewModel(300, 270));
items.Add(new CircleViewModel(350, 100));
items.Add(new CircleViewModel(50, 315));
items.Add(new CircleViewModel(100, 170));
}
}
public class ItemViewModel
{
// position coordinates
public double X { get; set; }
public double Y { get; set; }
}
public class CircleViewModel : ItemViewModel
{
// Constructors
public CircleViewModel(double x, double y)
{
this.X = x;
this.Y = y;
}
}
public class RectangleViewModel : ItemViewModel
{
// Constructors
public RectangleViewModel(double x, double y)
{
this.X = x;
this.Y = y;
}
}
}
UPDATED - Closer - ATTEMPT #2
Now I have the ability to drag and move items in the canvas with the hitTest of the click being correct. However for some reason when i try to move shapes in the bottom blue canvas they don't move, where as they do move in the top one. Try it out....
MainWindow.xaml.cs
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace DragShapes
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
bool captured = false;
double x_shape, x_canvas, y_shape, y_canvas;
UIElement source = null;
private void shape_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
{
Console.WriteLine("MouseDown--Pressed");
source = (UIElement)sender;
Mouse.Capture(source);
captured = true;
x_shape = Canvas.GetLeft(source);
x_canvas = e.GetPosition(LayoutRoot).X;
y_shape = Canvas.GetTop(source);
y_canvas = e.GetPosition(LayoutRoot).Y;
}
private void shape_MouseMove(object sender, MouseEventArgs e)
{
if (captured)
{
Console.WriteLine("MouseMove--Pressed");
double x = e.GetPosition(LayoutRoot).X;
double y = e.GetPosition(LayoutRoot).Y;
x_shape += x - x_canvas;
Canvas.SetLeft(source, x_shape);
x_canvas = x;
y_shape += y - y_canvas;
Canvas.SetTop(source, y_shape);
y_canvas = y;
}
}
private void
shape_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
Console.WriteLine("MouseUp--Pressed");
Mouse.Capture(null);
captured = false;
}
}
}
MainWindowViewModel.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace DragShapes
{
public class MainWindowViewModel
{
private ObservableCollection<ItemViewModel> items = new ObservableCollection<ItemViewModel>();
public ObservableCollection<ItemViewModel> Items { get { return items; } }
public MainWindowViewModel()
{
// Populate the view model with some example data.
items.Add(new RectangleViewModel(250, 200));
items.Add(new RectangleViewModel(320, 370));
items.Add(new RectangleViewModel(100, 50));
items.Add(new RectangleViewModel(350, 25));
items.Add(new RectangleViewModel(70, 270));
items.Add(new CircleViewModel(20, 20));
items.Add(new CircleViewModel(300, 270));
items.Add(new CircleViewModel(350, 100));
items.Add(new CircleViewModel(50, 315));
items.Add(new CircleViewModel(100, 170));
}
}
public class ItemViewModel : INotifyPropertyChanged
{
// position coordinates
private double x = 0;
public double X
{
get { return x; }
set
{
if (x != value)
{
x = value;
OnPropertyChanged("X");
}
}
}
private double y = 0;
public double Y
{
get { return y; }
set
{
if (y != value)
{
y = value;
OnPropertyChanged("Y");
}
}
}
protected void OnPropertyChanged(string name)
{
if (PropertyChanged != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(name));
}
}
public event PropertyChangedEventHandler PropertyChanged;
}
public class CircleViewModel : ItemViewModel
{
// Constructors
public CircleViewModel(double x, double y)
{
this.X = x;
this.Y = y;
}
}
public class RectangleViewModel : ItemViewModel
{
// Constructors
public RectangleViewModel(double x, double y)
{
this.X = x;
this.Y = y;
}
}
}
MainWindow.xaml
<Window x:Class="DragShapes.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="600" Width="600"
xmlns:local="clr-namespace:DragShapes">
<Window.DataContext>
<local:MainWindowViewModel />
</Window.DataContext>
<Window.Resources>
<DataTemplate DataType="{x:Type local:RectangleViewModel}" >
<Rectangle Cursor="Hand" Fill="Green" Width="100" Height="100" Margin="10"
MouseLeftButtonDown="shape_MouseLeftButtonDown"
MouseMove="shape_MouseMove"
MouseLeftButtonUp="shape_MouseLeftButtonUp"/>
</DataTemplate>
<DataTemplate DataType="{x:Type local:CircleViewModel}" >
<Path Data="M0,0 C0,0 10,100 100,100" Stroke="Gold" StrokeThickness="5" Cursor="Hand"
MouseLeftButtonDown="shape_MouseLeftButtonDown"
MouseLeftButtonUp="shape_MouseLeftButtonUp"
MouseMove="shape_MouseMove"/>
</DataTemplate>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Canvas x:Name="LayoutRoot" Background="White">
<Ellipse Fill="Blue" HorizontalAlignment="Center" Height="100" Stroke="Black" VerticalAlignment="Center" Width="100" Canvas.Left="200" Canvas.Top="100"
MouseLeftButtonDown="shape_MouseLeftButtonDown"
MouseMove="shape_MouseMove"
MouseLeftButtonUp="shape_MouseLeftButtonUp" />
<Rectangle Fill="Red" Height="100" Stroke="Black" Width="100" HorizontalAlignment="Left" VerticalAlignment="Bottom" Canvas.Left="10" Canvas.Top="10"
MouseLeftButtonDown="shape_MouseLeftButtonDown"
MouseLeftButtonUp="shape_MouseLeftButtonUp"
MouseMove="shape_MouseMove"/>
</Canvas>
<Canvas Grid.Row="1" Background="White" >
<ItemsControl ItemsSource="{Binding Path=Items}" >
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas Background="LightBlue" Width="500" Height="500" />
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<!--<ItemsControl.ItemTemplate>
<DataTemplate>
<Ellipse Fill="Green" Width="25" Height="25"
MouseLeftButtonDown="shape_MouseLeftButtonDown"
MouseLeftButtonUp="shape_MouseLeftButtonUp"
MouseMove="shape_MouseMove"/>
</DataTemplate>
</ItemsControl.ItemTemplate>-->
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Canvas.Top" Value="{Binding Path=Y}" />
<Setter Property="Canvas.Left" Value="{Binding Path=X}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
<!--<ItemsControl ItemsSource="{Binding Path=Items}">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Canvas/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X}"/>
<Setter Property="Canvas.Top" Value="{Binding Y}"/>
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>-->
<!--<ItemsControl ItemsSource="{Binding Path=Items}">
--><!--<ItemsControl.ItemContainerStyle>
<Style TargetType="ContentPresenter">
<Setter Property="Canvas.Left" Value="{Binding X}"/>
<Setter Property="Canvas.Top" Value="{Binding Y}"/>
</Style>
</ItemsControl.ItemContainerStyle>--><!--
</ItemsControl>-->
</Canvas>
</Grid>
</Window>
Default ListBoxItem template has active background, so we need reset the template like this:
<ListBox.ItemContainerStyle>
<Style TargetType="ListBoxItem" >
<Setter Property="Canvas.Left" Value="{Binding X}" />
<Setter Property="Canvas.Top" Value="{Binding Y}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ListBoxItem}">
<ContentPresenter/>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter Property="Background" Value="LightBlue"/>
</Trigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ListBox.ItemContainerStyle>
Then, we need modify the rectangle and circle templates, to get selection effect, when they are selected:
<DataTemplate DataType="{x:Type local:RectangleViewModel}" >
<Grid>
<Border CornerRadius="4"
Background="{Binding
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}},
Path=Background}"/>
<Border Cursor="Hand" Background="Green" CornerRadius="4" Width="100" Height="100" Margin="10"/>
</Grid>
</DataTemplate>
<DataTemplate DataType="{x:Type local:CircleViewModel}" >
<Grid>
<Path Data="M0,0 C0,0 10,100 100,100" StrokeThickness="15"
Stroke="{Binding
RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type ListBoxItem}},
Path=Background}"/>
<Path Data="M0,0 C0,0 10,100 100,100" Stroke="Gold" StrokeThickness="5" Cursor="Hand"/>
</Grid>
</DataTemplate>