I have a RadTreeListView and I want to display the image on the row where no child exists. Remaining nodes has children so they appears with Expand/Collapse sign. I read up on HierarchicalDataTemplates, but not sure how to use it on RadTreeListView. Any suggestions?
XAML :
<UserControl x:Class="ExpandCollapseImage.MainPage"
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:telerikSdk="http://schemas.telerik.com/2008/xaml/presentation"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="400">
<Grid x:Name="LayoutRoot" Background="White">
<telerikSdk:RadTreeListView x:Name="radTreeListView" AutoGenerateColumns="False" >
<telerikSdk:RadTreeListView.ChildTableDefinitions>
<telerikSdk:TreeListViewTableDefinition ItemsSource="{Binding Items}" />
</telerikSdk:RadTreeListView.ChildTableDefinitions>
<telerikSdk:RadTreeListView.Columns>
<telerikSdk:GridViewDataColumn DataMemberBinding="{Binding Name}" Header="Name" />
<telerikSdk:GridViewDataColumn DataMemberBinding="{Binding Count}" Header="Count" />
</telerikSdk:RadTreeListView.Columns>
</telerikSdk:RadTreeListView>
</Grid>
</UserControl>
XAML.CS :
using System.Windows.Controls;
using System.Collections.ObjectModel;
namespace ExpandCollapseImage
{
public partial class MainPage : UserControl
{
public MainPage()
{
InitializeComponent();
BindData();
}
public class WarehouseItem
{
public WarehouseItem(string name, int count, string imageUri)
{
this.Name = name;
this.Count = count;
this.Items = new ObservableCollection<WarehouseItem>();
this.Photo = imageUri;
}
public string Name { get; set; }
public ObservableCollection<WarehouseItem> Items { get; set; }
public int Count { get; set; }
public string Photo { get; set; }
}
public class WarehouseService
{
public static ObservableCollection<WarehouseItem> GetWarehouseData()
{
//System.Windows.Controls.Image img = new System.Windows.Controls.Image();
////img.Cursor = Cursors.Hand;
//img.Source = new BitmapImage(new Uri("/Images/Add.png", UriKind.RelativeOrAbsolute));
ObservableCollection<WarehouseItem> data = new ObservableCollection<WarehouseItem>();
WarehouseItem drinks = new WarehouseItem("Drinks", 35, string.Empty);
drinks.Items.Add(new WarehouseItem("Water", 10, string.Empty));
WarehouseItem tea = new WarehouseItem("Tea", 20, string.Empty);
tea.Items.Add(new WarehouseItem("Black", 10, string.Empty));
tea.Items.Add(new WarehouseItem("Green", 10, string.Empty));
drinks.Items.Add(tea);
drinks.Items.Add(new WarehouseItem("Coffee", 5, string.Empty));
data.Add(drinks);
WarehouseItem vegetables = new WarehouseItem("Vegeatbles", 75, string.Empty);
vegetables.Items.Add(new WarehouseItem("Tomato", 40, string.Empty));
vegetables.Items.Add(new WarehouseItem("Carrot", 25, string.Empty));
vegetables.Items.Add(new WarehouseItem("Onion", 10, string.Empty));
data.Add(vegetables);
WarehouseItem fruits = new WarehouseItem("Fruits", 55, string.Empty);
fruits.Items.Add(new WarehouseItem("Cherry", 30, string.Empty));
fruits.Items.Add(new WarehouseItem("Apple", 20, string.Empty));
fruits.Items.Add(new WarehouseItem("Melon", 5, string.Empty));
data.Add(fruits);
WarehouseItem Soda = new WarehouseItem("Soda", 10, "/Images/Add.png");
data.Add(Soda);
return data;
}
}
public void BindData()
{
this.radTreeListView.ItemsSource = WarehouseService.GetWarehouseData();
}
}
}
DESIRED OUTPUT :
Related
I'm trying to keep a combo box in sync with a property:
<ComboBox SelectedItem="{Binding StrokeSwatch}"...
This work excepts the combo box keeps being empty (items are here if the box is opened, but there is no current/selected item) until I manually select a value.
It should display the Red swatch and name:
I can't find the reason: The property SelectedItem is bound to (StrokeSwatch) has a value, which is used by the line, but the combo box doesn't react to this value.
Learning WPF, would appreciate a little help to understand.
The code...
<Window x:Class="WpfApp1.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:WpfApp1"
mc:Ignorable="d"
Title="MainWindow" Height="250" Width="300">
<Window.DataContext>
<local:ViewModel/>
</Window.DataContext>
<StackPanel Margin="10">
<StackPanel Orientation="Horizontal" Margin="10">
<TextBlock Text="Stroke:"/>
<ComboBox Margin="10,0,0,0" ItemsSource="{Binding SwatchesByName}" SelectedItem="{Binding StrokeSwatch}">
<ComboBox.ItemTemplate>
<DataTemplate>
<StackPanel Orientation="Horizontal">
<Rectangle Width="25" Fill="{Binding Brush}"/>
<TextBlock Margin="10,0,0,0" Text="{Binding Name}"/>
</StackPanel>
</DataTemplate>
</ComboBox.ItemTemplate>
</ComboBox>
</StackPanel>
<Line Margin="10" X1="0" Y1="0" X2="200" Y2="100"
Stroke="{Binding StrokeSwatch.Brush}"
StrokeThickness="2"/>
</StackPanel>
</Window>
C#:
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Windows;
using System.Windows.Media;
namespace WpfApp1 {
public partial class MainWindow : Window {
public MainWindow () {
InitializeComponent ();
}
}
public class ViewModel : INotifyPropertyChanged {
Swatch strokeSwatch;
public IEnumerable<Swatch> SwatchesByName { get => Swatches.ByName; }
public Swatch StrokeSwatch { get => strokeSwatch; set { strokeSwatch = value; RaisePropertyChanged (); } }
public event PropertyChangedEventHandler PropertyChanged;
public ViewModel () {
StrokeSwatch = Swatches.ColorToSwatch (Colors.Red);
}
void RaisePropertyChanged ([CallerMemberName] string propertyName = null) {
PropertyChanged?.Invoke (this, new PropertyChangedEventArgs (propertyName));
}
}
static class Swatches {
public static IEnumerable<Swatch> ByName { get; }
static Swatches () {
ByName = from PropertyInfo pi in typeof (Colors).GetProperties ()
orderby pi.Name
select new Swatch (pi.Name, (Color) pi.GetValue (null, null));
}
public static Swatch ColorToSwatch (Color color) {
return ByName.First (sw => sw.Color == color);
}
}
public class Swatch {
SolidColorBrush brush;
public string Name { get; }
public Color Color { get; }
public SolidColorBrush Brush { get { if (brush == null) brush = new SolidColorBrush (Color); return brush; } }
public Swatch (string name, Color color) {
Name = name;
Color = color;
}
}
}
Call ToArray() on the IEnumerable<Swatch> to materialize the ByName collection:
static Swatches()
{
ByName = (from PropertyInfo pi in typeof(Colors).GetProperties()
orderby pi.Name
select new Swatch(pi.Name, (Color)pi.GetValue(null, null))).ToArray();
}
First of all you should use observableCollection property and return List in your Swatche class
public class ViewModel : INotifyPropertyChanged
{
Swatch strokeSwatch;
public ObservableCollection<Swatch> SwatchesByName
{
get => _swatchesByName;
set { _swatchesByName = value; RaisePropertyChanged();}
}
private ObservableCollection<Swatch> _swatchesByName;
public Swatch StrokeSwatch
{
get => strokeSwatch;
set { strokeSwatch = value; RaisePropertyChanged(); }
}
public event PropertyChangedEventHandler PropertyChanged;
public ViewModel()
{
SwatchesByName = new ObservableCollection<Swatch>(Swatches.ByName);
StrokeSwatch = Swatches.ColorToSwatch(Colors.Red);
}
void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
static class Swatches
{
public static List<Swatch> ByName { get; }
static Swatches()
{
var list = from PropertyInfo pi in typeof(Colors).GetProperties()
orderby pi.Name
select new Swatch(pi.Name, (Color)pi.GetValue(null, null));
ByName = list.ToList();
}
public static Swatch ColorToSwatch(Color color)
{
return ByName.First(sw => sw.Color == color);
}
}
public class Swatch
{
SolidColorBrush brush;
public string Name { get; }
public Color Color { get; }
public SolidColorBrush Brush
{
get { if (brush == null) brush = new SolidColorBrush(Color); return brush; }
}
public Swatch(string name, Color color)
{
Name = name;
Color = color;
}
}
This question already has answers here:
Unable to display list items in DataGrid in WPF
(2 answers)
Closed 4 years ago.
I'm new to WPF and MVVM. I'm trying to use a Datagrid along with a Collectionviewsource in my project. I have worked up to some level as below, but my Datagrid is not showing any rows. Below is the code parts. I'm trying to figure what I am missing here. Note that I am only publishing the code parts which are necessary to this problem.
ScanBatchWindow.xaml.cs
public partial class ScanBatchWindow : Window
{
public ScanBatchWindow()
{
InitializeComponent();
ScanBatchViewModel pMV = new ScanBatchViewModel();
this.DataContext = pMV;
}
}
ScanBatchWindow.xaml
<Window x:Class="BatchManPOC.ScanBatchWindow"
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:BatchManPOC"
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:cmdBehavior="clr-namespace:BatchManPOC.CmdBehavior"
xmlns:video="clr-namespace:BatchManPOC.Video"
xmlns:Custom="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
mc:Ignorable="d"
Title="ScanBatchWindow"
Height="800"
Width="800">
<Window.Resources>
<CollectionViewSource Source="{Binding p_ListBatches}" x:Key="CVS"/>
</Window.Resources>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
</Grid.RowDefinitions>
<Custom:DataGrid ItemsSource="{Binding Source={StaticResource CVS}}" Margin="8" Grid.Row="0" AutoGenerateColumns="True" IsReadOnly="True">
</Custom:DataGrid>
</Grid>
</Window>
ScanBatchViewModel.cs
Note that I have a BaseViewModel which inherit from INotifyPropertyChanged.
public class ScanBatchViewModel : BaseViewModel
{
public CollectionViewSource CVS { get; set; }
public ObservableCollection<Batch> p_ListBatches { get; set; }
public class Batch
{
public DateTime p_dCreated;
public int p_iReference;
public BatchStatus p_iBatchStatus;
public string p_sFromBranch;
}
/// <summary>
/// Initializes a new instance of the ScanBatchViewModel class.
/// </summary>
public ScanBatchViewModel()
{
LoadBatches();
CVS = new CollectionViewSource();
}
public void LoadBatches()
{
//Add sample objects
p_ListBatches.Add(new Batch() { p_dCreated = DateTime.Now, p_iBatchStatus = BatchStatus.DOC_STATUS_CREATED, p_iReference = 1, p_sFromBranch = "7010888" });
p_ListBatches.Add(new Batch() { p_dCreated = DateTime.Now, p_iBatchStatus = BatchStatus.DOC_STATUS_DELETED, p_iReference = 2, p_sFromBranch = "7010999" });
p_ListBatches.Add(new Batch() { p_dCreated = DateTime.Now, p_iBatchStatus = BatchStatus.DOC_STATUS_RECEIVED, p_iReference = 3, p_sFromBranch = "7010000" });
p_ListBatches.Add(new Batch() { p_dCreated = DateTime.Now, p_iBatchStatus = BatchStatus.DOC_STATUS_SENT, p_iReference = 4, p_sFromBranch = "7010777" });
}
}
Thanks, I found the answer. I have not defined members of the Batch class as properties. Therefore, although we set the values to public members, they will not appear in the .XAML since they are not exposed as properties. Changing them as below worked for me.
public class Batch
{
public DateTime p_dCreated { get; set; }
public int p_iReference { get; set; }
public BatchStatus p_iBatchStatus { get; set; }
public string p_sFromBranch { get; set; }
}
I have a listview whose item template is a treeview( having fixed height and width). Not much xaml or code to post .
Now I can scroll the list if the mouse is not over the TreeView.
How can I scroll the list even if the mouse is over any TreeView?
We can solve this with some behavior. Simple example:
Behavior with comments:
public sealed class ScrollParentBehavior : Behavior<UIElement>
{
protected override void OnAttached()
{
base.OnAttached();
AssociatedObject.PreviewMouseWheel += AssociatedObjectOnPreviewMouseWheel;
}
protected override void OnDetaching()
{
AssociatedObject.PreviewMouseWheel -= AssociatedObjectOnPreviewMouseWheel;
base.OnDetaching();
}
private void AssociatedObjectOnPreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
// find parent, it will be ContentPresenter
var parent = VisualTreeHelper.GetParent(AssociatedObject) as UIElement;
if (parent == null) return;
// handle event
// We can create here some logic, if we need to scroll TreeView content
e.Handled = true;
// raise it on parent
parent.RaiseEvent(new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
{
RoutedEvent = UIElement.MouseWheelEvent
});
}
}
And usage - ListView and TreeView in ItemTemplate.
<ListView ItemsSource="{Binding}">
<ListView.ItemTemplate>
<DataTemplate>
<TreeView Width="100" Height="100">
<i:Interaction.Behaviors>
<local:ScrollParentBehavior />
</i:Interaction.Behaviors>
</TreeView>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
Don't forget about xmlns for XAML:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
And System.Windows.Interactivity in references.
You can set IsHitTestVisible="False" for TreeView.
Simple example:
<Window x:Class="WpfApplication6.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ListView Margin="10" x:Name="lvDataBinding" >
<ListView.ItemTemplate>
<DataTemplate>
<TreeView IsHitTestVisible="False">
<TreeViewItem Header="{Binding Id}" />
<TreeViewItem Header="{Binding Name}" />
<TreeViewItem Header="{Binding Details}" />
</TreeView>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<User> users = new List<User>();
users.Add(new User() { Id = 1, Name = "John Doe", Birthday = new DateTime(1971, 7, 23) });
users.Add(new User() { Id = 2, Name = "Jane Doe", Birthday = new DateTime(1974, 1, 17) });
users.Add(new User() { Id = 3, Name = "Sammy Doe", Birthday = new DateTime(1991, 9, 2) });
users.Add(new User() { Id = 4, Name = "Sammy Doe1", Birthday = new DateTime(1991, 9, 2) });
users.Add(new User() { Id = 5, Name = "Sammy Doe2", Birthday = new DateTime(1991, 9, 2) });
users.Add(new User() { Id = 6, Name = "Sammy Doe3", Birthday = new DateTime(1991, 9, 2) });
lvDataBinding.ItemsSource = users;
}
}
public class User
{
public int Id { get; set; }
public string Name { get; set; }
public DateTime Birthday { get; set; }
public string Details
{
get
{
return String.Format("{0} was born on {1} and this is a long description of the person.", this.Name, this.Birthday.ToLongDateString());
}
}
}
I have a list of objects, each contains a collection. I need a possibility to select a object from the list and display the collection. The collection should be sorted by a some property.
So, I have a ComboBox to display a list of objects. And a DataGrid to display a selected object's collection. I use a CollectionViewSource to sort a DataGrid. It work... but only first time. After selecting other object from the list, DataGrid are no longer sorted.
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:componentModel="clr-namespace:System.ComponentModel;assembly=WindowsBase"
Title="MainWindow" Height="350" Width="525">
<Window.Resources>
<ResourceDictionary>
<CollectionViewSource x:Key="SortedValues"
Source="{Binding SelectedCategory.Values}">
<CollectionViewSource.SortDescriptions>
<componentModel:SortDescription PropertyName="Value" Direction="Ascending" />
</CollectionViewSource.SortDescriptions>
</CollectionViewSource>
</ResourceDictionary>
</Window.Resources>
<Grid>
<StackPanel>
<ComboBox ItemsSource="{Binding Path=Categories}"
DisplayMemberPath="Name"
SelectedItem="{Binding Path=SelectedCategory}"/>
<DataGrid ItemsSource="{Binding Source={StaticResource SortedValues}}"
CanUserSortColumns="False">
</DataGrid>
</StackPanel>
</Grid>
Code Behind:
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
namespace WpfApplication1
{
public partial class MainWindow : Window, INotifyPropertyChanged
{
public MainWindow()
{
InitializeComponent();
DataContext = this;
Categories = new ObservableCollection<MyCategory>
{
new MyCategory
{
Name = "Cat1",
Values = new ObservableCollection<MyValue>
{
new MyValue {Value = 5},
new MyValue {Value = 4},
new MyValue {Value = 3},
new MyValue {Value = 2},
new MyValue {Value = 1},
}
},
new MyCategory
{
Name = "Cat2",
Values = new ObservableCollection<MyValue>
{
new MyValue {Value = 15},
new MyValue {Value = 14},
new MyValue {Value = 13},
new MyValue {Value = 12},
new MyValue {Value = 11},
}
}
};
}
public ObservableCollection<MyCategory> Categories { get; set; }
public MyCategory SelectedCategory
{
get
{
return _selectedCategory;
}
set
{
_selectedCategory = value;
OnPropertyChanged();
}
}
private MyCategory _selectedCategory;
#region INotifyPropertyChanged
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
#endregion
}
public class MyCategory
{
public string Name { get; set; }
public ObservableCollection<MyValue> Values { get; set; }
}
public class MyValue
{
public double Value { get; set; }
}
}
I have 30+ big XML Files with 20-30 kb size, from which some information must be displayed in the DataGrid as one datasource. How can I make a binding 1(or 2 or 3 files) file to the 1 row of DataGrid?
For example, this part of XML-file:
<NameId>4366527</NameId>
<TargetType>2</TargetType>
<TargetCost>21</TargetCost>
<Tag>11</Tag>
<SupplyingRate>100</SupplyingRate>
<SupplyType>0</SupplyType>
<Transparency>0</Transparency>
<Passability>100</Passability>
<HumanPassability>100</HumanPassability>
And this part of another file:
<NameId>6591314</NameId>
<TargetType>2</TargetType>
<TargetCost>26</TargetCost>
<Tag>11</Tag>
<SupplyingRate>100</SupplyingRate>
<SupplyType>0</SupplyType>
<Transparency>0</Transparency>
<Passability>100</Passability>
<HumanPassability>100</HumanPassability>
Must be displayed in one Datagrid:
<dg:DataGrid Grid.Row="1" ItemsSource="{Binding Source={StaticResource Orders}}"
AutoGenerateColumns="True" RowEditEnding="DataGrid_RowEditEnding">
<dg:DataGrid.Columns>
<dg:DataGridTextColumn Header="NameId" />
<dg:DataGridTextColumn Header="TargetType" />
<dg:DataGridTextColumn Header="TargetCost" />
<dg:DataGridTextColumn Header="Tag" />
<dg:DataGridTextColumn Header="SupplyingRate" />
<dg:DataGridTextColumn Header="SupplyType" />
<dg:DataGridTextColumn Header="Transparency" />
<dg:DataGridTextColumn Header="Passability" />
<dg:DataGridTextColumn Header="HumanPassability" />
</dg:DataGrid.Columns>
</dg:DataGrid>
The first thing you have to do is create a class to contain XML data, like this one:
public class MyData
{
public int NameId { get; set; }
public int TargetType { get; set; }
public int TargetCost { get; set; }
public int Tag { get; set; }
public int SupplyingRate { get; set; }
public int SupplyType { get; set; }
public int Transparency { get; set; }
public int Passability { get; set; }
public int HumanPassability { get; set; }
}
Then you need to create the ViewModel for your DataGrid, for example:
public ObservableCollection<MyData> MyList { get; set; }
public ViewModel()
{
MyList = new ObservableCollection<MyData>();
MyData data = new MyData()
{
NameId = 4366527,
TargetType = 2,
TargetCost = 21,
Tag = 11,
SupplyingRate = 100,
SupplyType = 0,
Transparency = 0,
Passability = 100,
HumanPassability = 100
};
MyList.Add(data);
data = new MyData()
{
NameId = 6591314,
TargetType = 2,
TargetCost = 26,
Tag = 11,
SupplyingRate = 100,
SupplyType = 0,
Transparency = 0,
Passability = 100,
HumanPassability = 100
};
MyList.Add(data);
}
MyList is a collection which contains all the data you read from your XMLs. Obviously, in this example, I populate it with data samples. You have to provide the code to fill it.
After that, you have to create your DataGrid. I put it in a Windows and the code is:
<Window x:Class="Temp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525"
xmlns:local="clr-namespace:Temp">
<Window.DataContext>
<local:ViewModel />
</Window.DataContext>
<Grid>
<DataGrid ItemsSource="{Binding Path=MyList}"
AutoGenerateColumns="True">
</DataGrid>
</Grid>
</Window>