MenuItem binding datacontext in listview - c#

I have a ListView with a DataTemplate, inside this templates there are several textblocks and a button. The button has a contextmenu with fixed items. The binding of the listviewitems works fine, but binding a property to the contextmenu does not seem to work.
<ListView x:Name="lv_clients" Margin="0 22 0 0" SelectionMode="Single">
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid Grid.Column="0" Grid.RowSpan="2" Background="{Binding StateColor}">
</Grid>
<TextBlock Grid.Column="1" Text="{Binding DisplayString}" Foreground="Black" Height="20" FontWeight="Bold" Padding="2,2,0,0" />
<Button Click="Button_ListItem_Click" Grid.Column="1" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Top">
<Button.ContextMenu>
<ContextMenu>
<MenuItem Header="Anrufen" Name="mn_call" Click="mn_call_Click" DataContext={Binding Number} />
</ContextMenu>
</Button.ContextMenu> ...</Button>
<StackPanel Grid.Column="1" Grid.Row="1">
<TextBlock Text="{Binding State}" Height="20" Padding="2,2,0,0"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="{Binding FirstEntry.KDKGRS}" Height="20" FontWeight="Bold" Padding="2,2,2,0" HorizontalAlignment="Left" Foreground="{Binding FirstEntry.ConvertedKGFARBE}" />
<TextBlock Text="{Binding FirstEntry.ADNAMI}" Height="20" Padding="0,2,0,0" HorizontalAlignment="Left" />
</StackPanel>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
I have removed some unnecessary bits of the code (style and columndefinitions) for readability.
The important part is the MenuItem inside the Button. My underlying class has a public string property Number. This should be passed to the menu item. But the DataContext of the MenuItem is always null inside the click event.
I've read something about the contextmenu not beeing part of the visual tree, but I can't wrap my head around it. Could somebody explain the issue with the binding?
Edit Code for the underlying class:
Again removed some unnecessary code for the question
public class PhoneClient
{
public String Name { get; set; }
public String Number { get; set; }
public String Extension { get; set; }
public String DisplayString
{
get
{
return String.IsNullOrEmpty(Name) ? Number : String.Format("{0} ({1})", Name, Extension);
}
}
}
And the binding of the ListBox:
List<PhoneClient> clients = new List<PhoneClient>();
clients = load(); //returns active Clients
lv_clients.ItemsSource = clients;

Bridging the gap
<ContextMenu Tag="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Anrufen" Click="mn_call_Click" Name="mn_call"
DataContext="{Binding Tag.Number, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" />
</ContextMenu>
Handler
private void mn_call_Click(object sender, RoutedEventArgs e)
{
MenuItem currentMenuItem = (MenuItem)sender;
string number = (string)currentMenuItem.DataContext;
// Do Stuff
}
EDIT
MainWindow.xaml
<Window x:Class="WpfApp.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 Margin="10">
<ListView x:Name="lv_clients" Margin="0 22 0 0" SelectionMode="Single">
<ListView.ItemTemplate>
<DataTemplate>
<Grid Background="LightGray" Width="100">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid Background="LightGreen">
</Grid>
<TextBlock Text="{Binding DisplayString}" Foreground="Black" Height="20" FontWeight="Bold" Padding="2,2,0,0" />
<Button Click="Button_ListItem_Click" Grid.Row="0" HorizontalAlignment="Right" VerticalAlignment="Top">
<Button.ContextMenu>
<ContextMenu Tag="{Binding PlacementTarget.DataContext, RelativeSource={RelativeSource Self}}">
<MenuItem Header="Show" Click="mn_call_Click" Name="mn_call" DataContext="{Binding Tag.Number, RelativeSource={RelativeSource AncestorType={x:Type ContextMenu}}}" />
</ContextMenu>
</Button.ContextMenu> ...
</Button>
<StackPanel Grid.Row="1">
<TextBlock Text="{Binding State}" Height="20" Padding="2,2,0,0"/>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Foo" Height="20" FontWeight="Bold" Padding="2,2,2,0" HorizontalAlignment="Left" Foreground="Blue" />
<TextBlock Text="Bar" Height="20" Padding="0,2,0,0" HorizontalAlignment="Left" />
</StackPanel>
</StackPanel>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</Window>
MainWindow.xaml.cs
using System;
using System.Windows;
using System.Windows.Controls;
using System.Collections.Generic;
namespace WpfApp
{
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
List<PhoneClient> clients = new List<PhoneClient>();
clients.Add(new PhoneClient() { Name = "Kumar", Number = "0101010", Extension = "555", State = "New York" });
clients.Add(new PhoneClient() { Name = "Shanaya", Number = "1010101", Extension = "555", State = "New Jersey" });
clients.Add(new PhoneClient() { Name = "Billy Bob", Number = "6543210", Extension = "555", State = "Single" });
lv_clients.ItemsSource = clients;
}
public class PhoneClient
{
public String Name { get; set; }
public String Number { get; set; }
public String Extension { get; set; }
public String State { get; set; }
public String DisplayString
{
get
{
return String.IsNullOrEmpty(Name) ? Number : String.Format("{0} ({1})", Name, Extension);
}
}
}
private void mn_call_Click(object sender, RoutedEventArgs e)
{
MenuItem currentMenuItem = (MenuItem)sender;
string number = (string)currentMenuItem.DataContext;
MessageBox.Show("Number " + number);
}
private void Button_ListItem_Click(object sender, RoutedEventArgs e)
{
Button currentButton = (Button)sender;
PhoneClient data = (PhoneClient)currentButton.DataContext;
MessageBox.Show(data.Name + " tapped");
}
}
}

Related

How to use selected items from a listview in multiple views

I have a separate view that contains an observable collection and would like to use the selected item from the collection in another view (MainView). Can anyone tell me how to implement the property change in the MainView?
The Main Window:
<Window.DataContext>
<local:MainWindowViewModel x:Name="mainWindowViewModel"/>
</Window.DataContext>
<Window.Resources>
<view:OwnerListViewModel x:Key="OwnerList"/>
</Window.Resources>
<TextBlock Height="25" Margin="0 5 0 0" Grid.Row="1" Grid.Column="0" Text="{Binding
PersonModel.FirstName}" ></TextBlock>
<TextBlock Height="25" Margin="0 5 0 0" Grid.Row="1" Grid.Column="1" Text="{Binding
PersonModel.SurName}" Grid.ColumnSpan="2"></TextBlock>
In MainWindowViewModel:
private OwnerListViewModel OwnerListViewModel { get; } = new OwnerListViewModel();
public Owner PersonModel
{
get { return OwnerListViewModel.PersonModel; }
set { OwnerListViewModel.PersonModel = value; OnPropertyChanged(); }
}
In the LoadOwner Window, i created the ListView:
<Window.DataContext>
<view:OwnerListViewModel/>
</Window.DataContext>
<ListView Grid.Column="0" ItemsSource="{Binding PersonsView}" SelectedValue="{Binding
PersonModel, Mode=TwoWay}">
<i:Interaction.Triggers>
<i:EventTrigger EventName="SelectionChanged">
<i:InvokeCommandAction Command="{Binding SelectionChangedCmd}"
CommandParameter="{Binding
ElementName=PersonListWindow}"/>
</i:EventTrigger>
</i:Interaction.Triggers>
<ListView.ItemTemplate>
<DataTemplate>
<Grid Height="auto">
<Grid.ColumnDefinitions>
<ColumnDefinition></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<TextBlock Grid.Column="0" Margin="0 0 5 0" VerticalAlignment="Center"
Text="{Binding FirstName}"/>
<TextBlock Grid.Column="1" VerticalAlignment="Center"
Text="{Binding SurName}"/>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
My OwnerListViewModel:
Here I am not sure how to implement the property change. Using an asynchronous task, or are there other options? I would be very grateful for a tip!
public OwnerListViewModel()
{
Persons = new ObservableCollection<Owner>();
var sample1 = new Owner()
{
FirstName = "SampleFirstName1",
SurName = "SampleLastname1",
Street = "SampleStreet1",
HouseNumber = 987,
AdditionalAdress = "",
ZipCode = 99999,
City = "SampleCity1"
};
AddOwner(sample1);
PersonsView = CollectionViewSource.GetDefaultView(Persons);
PersonsView.CurrentChanged += (s, e) =>
{
OnPropertyChanged(() => PersonModel);
};
SelectionChangedCmd = new RelayCommand<Window>(this.closeWindow);
}
#region listProperties
private ObservableCollection<Owner> Persons { get; }
public ICollectionView PersonsView { get; set; }
public Owner PersonModel
{
get => PersonsView.CurrentItem as Owner;
set
{
PersonsView.MoveCurrentTo(value);
OnPropertyChanged();
}
}
You created different objects of OwnerListViewModel. One way is deleting this code from 2 views:
<Window.Resources>
<view:OwnerListViewModel x:Key="OwnerList"/>
</Window.Resources>
and bind datacontext in view codebehind:
var ownerListViewModel = new OwnerListViewModel();
LoadOwnerWindow.DataContext = ownerListViewModel;
MainView.DataContext = ownerListViewModel.PersonModel;
Also you can use IoC to bind view models.
Also, the other way is using WPF messenger to send changed owner as a message from LoadOwnerWindow to MainView
the solution is to set the data context directly in the main window:
<TextBox Height="25" Margin="0 5 0 0" Grid.Row="1" Grid.Column="0" DataContext="{Binding OwnerListViewModel.SelectedItem}" Text="{Binding FirstName}" ></TextBox>
<TextBox Height="25" Margin="0 5 0 0" Grid.Row="1" Grid.Column="1" DataContext="{Binding OwnerListViewModel.SelectedItem}" Text="{Binding SurName}" Grid.ColumnSpan="2"></TextBox>

Could not pass values from view to viewmodel through commands

I am implementing MVVM pattern for my application. I have my Views, ViewModel, Model and Commands and Converters being implemented. Now I am not able to pass my textboxes values from my datatemplate to my ViewModel through the command binding. I am able to click on the button to attempt the update process but its not able to pass the textboxes value. Are there something i need to change on my command class?
Here is my XAML:
<DataGrid AutoGenerateColumns="False" Grid.Row="2" Grid.ColumnSpan="4" Grid.RowSpan="3" x:Name="productionLineConfigDataGrid" Margin="70,0.2,70,0" ItemsSource="{Binding listAllProductionLineConfigs}">
<DataTemplate>
<StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="12" Text="ID: " VerticalAlignment="Center" />
<TextBlock x:Name="txtBlockLineId" FontSize="16" Foreground="MidnightBlue" Text="{Binding ProductionLineId, Mode=TwoWay}" VerticalAlignment="Center" />
</StackPanel>
<StackPanel>
<Button x:Name="btnUpdate" Content="Update" VerticalAlignment="Center" HorizontalAlignment="Right" Click="btnUpdate_Click" Command="{Binding DataContext.updateProductionLineConfigCommand, RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type local:production_line_config_home}}}" CommandParameter="{Binding ProductionLineConfig}"/>
</StackPanel>
</StackPanel>
</DataTemplate>
</DataGrid>
Here is the method from my ViewModel:
public ProductionLineConfig ProductionLineConfig
{
get { return productionlineconfig; }
set
{
productionlineconfig = value;
OnPropertyChanged("ProductionLineConfig");
}
}
This is the error message i am getting:
System.Windows.Data Error: 40 : BindingExpression path error: 'ProductionLineConfig' property not found on 'object' ''ProductionLineConfig' (HashCode=47309994)'. BindingExpression:Path=ProductionLineConfig; DataItem='ProductionLineConfig' (HashCode=47309994); target element is 'Button' (Name=''); target property is 'CommandParameter' (type 'Object')
I have included the image for my application here
This is the entire xaml code here and this is the entire viewmodel code here
I'm only going to take a guess at this.
Assuming ProductionLineConfig is what you are binding to for ProductionLineId in the template. Then you probably are just wanting to pass your binding source as the command parameter
CommandParameter="{Binding}"
When {Binding} is empty, it means the Binding is bound to whatever Source there is. Which is also just shorthand for...
{Binding DataContext,RelativeSource={RelativeSource Self}}.
In turn (if the stars align), then it should be your ProductionLineConfig
Based on your code source, I made a sample implementation, to achieve your requirement.
Sample VM:
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using System.Windows;
namespace WpfApp5.ViewModels
{
public class ProductionLineConfigViewModel : INotifyPropertyChanged
{
public CustomCommand<ProductionLineConfig> UpdateCommand { get; }
public ProductionLineConfigViewModel()
{
PopulateProductionLineConfigs();
UpdateCommand = new CustomCommand<ProductionLineConfig>(UpdateConfig, (u) => true);
}
private ObservableCollection<ProductionLineConfig> _listAllProductionLineConfigs;
public ObservableCollection<ProductionLineConfig> listAllProductionLineConfigs
{
get { return _listAllProductionLineConfigs; }
set
{
_listAllProductionLineConfigs = value;
OnPropertyChanged();
}
}
// Call this from constructor.
private void PopulateProductionLineConfigs()
{
listAllProductionLineConfigs = new ObservableCollection<ProductionLineConfig>
{
new ProductionLineConfig
{
ProductionLineId = 1,
ProductionLineCode = "001",
ProductionLineCreatedDate = DateTime.Today.Date,
ProductionLineName = "safdsf",
ProductionLineStatus = true
},
new ProductionLineConfig
{
ProductionLineId = 1,
ProductionLineCode = "002",
ProductionLineCreatedDate = DateTime.Today.Date,
ProductionLineName = "sadfadfsdf",
ProductionLineStatus = true
}
};
}
private void UpdateConfig(ProductionLineConfig config)
{
MessageBox.Show("Line Name update: " + config.ProductionLineName);
}
public event PropertyChangedEventHandler PropertyChanged;
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class ProductionLineConfig
{
public int ProductionLineId { get; set; }
public string ProductionLineCode { get; set; }
public string ProductionLineName { get; set; }
public bool ProductionLineStatus { get; set; }
public DateTime ProductionLineCreatedDate { get; set; }
}
}
Sample XAML:
<Window x:Name="Root" x:Class="WpfApp5.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:WpfApp5.ViewModels"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Window.DataContext>
<viewModels:ProductionLineConfigViewModel/>
</Window.DataContext>
<Grid Background="#FF006E8C">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Label Grid.ColumnSpan="4" Content="KAD ShopFloor System" HorizontalAlignment="Center" Margin="10" FontWeight="Bold" FontSize="30" FontFamily="Segoe UI" Foreground="White"/>
<Separator Grid.ColumnSpan="4" Grid.RowSpan="3" Background="White" Margin="0,-35,-0.4,39.2"/>
<DataGrid AutoGenerateColumns="False" Grid.Row="2" Grid.ColumnSpan="4" Grid.RowSpan="3" x:Name="productionLineConfigDataGrid" Margin="70,0.2,70,0"
ItemsSource="{Binding DataContext.listAllProductionLineConfigs, ElementName=Root}">
<DataGrid.Columns>
<DataGridTextColumn Header="ID" Binding="{Binding ProductionLineId, Mode=TwoWay}"/>
<DataGridTextColumn Header="Production Line Code" Binding="{Binding ProductionLineCode, Mode=TwoWay}"/>
<DataGridTextColumn Header="Production Line Name" Binding="{Binding ProductionLineName, Mode=TwoWay}"/>
<DataGridTextColumn Header="Status" Binding="{Binding ProductionLineStatus, Mode=TwoWay}"/>
<DataGridTextColumn Header="Created Date" Binding="{Binding ProductionLineCreatedDate, Mode=TwoWay}"/>
</DataGrid.Columns>
<DataGrid.RowDetailsTemplate>
<DataTemplate>
<Border BorderThickness="0" Background="BlanchedAlmond" Padding="10">
<StackPanel Orientation="Vertical" x:Name="stck">
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="12" Text="ID: " VerticalAlignment="Center" />
<TextBlock x:Name="txtBlockLineId" FontSize="16" Foreground="MidnightBlue" Text="{Binding ProductionLineId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="12" Text="Line Code: " VerticalAlignment="Center" />
<TextBlock x:Name="txtBlockLineCode" FontSize="16" Foreground="MidnightBlue" Text="{Binding ProductionLineCode, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="12" Text="Line Name: " VerticalAlignment="Center" />
<TextBox x:Name="txtLineName" FontSize="16" Foreground="MidnightBlue" Text="{Binding ProductionLineName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" VerticalAlignment="Center" />
</StackPanel>
<!--<StackPanel Orientation="Horizontal">
<TextBlock FontSize="12" Text="Status: " VerticalAlignment="Center" />
<ComboBox ItemsSource="{Binding RelativeSource={RelativeSource FindAncestor,AncestorType={x:Type DataGrid}},
Path=DataContext.Statusstring}" SelectedValue="{Binding ProductionLineStatus, Converter={StaticResource statusToBooleanConverter}, Mode=TwoWay}" x:Name="cbProductionLineStatus" FlowDirection="LeftToRight" FontSize="16" Foreground="MidnightBlue"
HorizontalAlignment="Stretch" VerticalAlignment="Center"/>
</StackPanel>-->
<StackPanel>
<Button x:Name="btnUpdate" Content="Update" VerticalAlignment="Center" HorizontalAlignment="Right"
Command="{Binding DataContext.UpdateCommand, ElementName=Root}"
CommandParameter="{Binding}" />
</StackPanel>
</StackPanel>
</Border>
</DataTemplate>
</DataGrid.RowDetailsTemplate>
</DataGrid>
</Grid>
</Window>
Sample output:
Key changes here,
You need to change your list to observable collection
Create a custom command that accepts an object, see this post: [UWP/MVVM]Enable/Disable Button in RadDataGrid Data Template Column that have commands bound to them upon conditions
Command Parameter should be the iterated item, can be achieve by CommandParameter={Binding}
In you two way bindings, make sure to add UpdateSourceTrigger=PropertyChanged

How to check to state of controls created dynamically using itemscontrol after naming them in the itemscontrol wpf C#

For my code, I've created multiple control of the same type (i.e. Checkbox) using itemscontrol bound to a class "MyClass". I've named the checkbox control as "checkControl". Now, as I've multiple checkbox control created in the UI, I want to check their state and differentiate among them. How should I proceed? I'm thinking of using findvisualchild & findvisualparent? But, I don't have any idea how to use it?
<ItemsControl Name="myList">
<ItemsControl.ItemTemplate>
<DataTemplate>
<Grid Margin="30,80,10,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Border x:Name="tempBorder" BorderBrush="LightGray" BorderThickness="2,2,2,2" CornerRadius="4,4,4,4" Margin="0,-30,-60,-30"
Background="LightGray">
<StackPanel Orientation="Horizontal" Background="Transparent" Margin="0">
<StackPanel Background="White" Orientation="Horizontal">
<CheckBox x:Name="checkControl" Margin="7,7,0,0" Checked="CheckBox_Checked" Unchecked="CheckBox_Unchecked">
<WrapPanel>
<Image Source="/Images/myimage.png" Margin="0,10,0,0"></Image>
<StackPanel Orientation="Vertical" VerticalAlignment="Center">
<TextBlock Text="{Binding Disk}" FontFamily="roboto" FontSize="14"/>
<Rectangle Width="340" Height="1" Margin="0,5,5,5" Fill="Black"/>
<TextBlock>
<Run Text="Item:" FontFamily="roboto" FontSize="14"/>
<Run Text="{Binding Path=Name, StringFormat=' {0} Jr.'}" FontSize="20" Foreground="Orange"
FontWeight="DemiBold"/>
</TextBlock>
</StackPanel>
</WrapPanel>
</CheckBox>
</StackPanel>
<StackPanel Orientation="Vertical" Background="LightGray" Margin="0" HorizontalAlignment="Center" Width="765"
VerticalAlignment="Center">
<TextBlock Text="Select the Option:" Margin="15,7,0,7" FontFamily="roboto"/>
<ComboBox x:Name="comboControl" Margin="15,5,0,7" Width="750" SelectionChanged="comboControl_SelectionChanged"/>
</StackPanel>
</StackPanel>
</Border>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
</ItemsControl>
For My Backend C# Code:
Class
public class MyClass
{
public string Disk { get; set; }
public string Name { get; set; }
public MyClass()
{
}
public MyClass(string album, string name)
{
this.Disk = album;
this.Name = name;
}
}
In my Xaml.cs
public ObservableCollection<MyClass> StudentDisk { get; set; }
//somecode
StudentDisk.Add(new MyClass("Disk 4 ", "John")); //For populating
//somecode
myList.ItemsSource = StudentDisk;
it is possible to differentiate checkBoxes by their DataContext, which should be unique:
void CheckBox_Checked(object sender, RoutedEventArgs e)
{
var checkbox = (CheckBox)sender;
var item = (MyClass)checkbox.DataContext;
MessageBox.Show(item.Disk + " " + item.Name);
}

How to show properties of listbox selected item in different controls

In my application I have a window which contain a ListBox, and controls that should show different properties of its currently selected item. Those controls are:
TextBox that should show 'Name' property.
TextBox that should show 'DataFile` property.
DataGrid that should show 'TItems property, which is an ObservableCollection.
I tried to bind SelectedItem to an object, and then bind different properties of that object to the controls mentioned above, with no success.
The window:
My View:
<Window
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:ReportMaker"
xmlns:ViewModel="clr-namespace:ReportMaker.ViewModel" x:Class="ReportMaker.MainWindow"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Window.DataContext>
<ViewModel:MainViewModel/>
</Window.DataContext>
<Grid>
<Button x:Name="button" Content="Create" HorizontalAlignment="Right" Margin="0,0,10,10" VerticalAlignment="Bottom" Width="75"/>
<ComboBox x:Name="comboBox" HorizontalAlignment="Left" Margin="10,0,0,10" VerticalAlignment="Bottom" Width="120"/>
<ListBox x:Name="listBox" HorizontalAlignment="Left" Margin="10,10,0,36.667" Width="119" ItemsSource="{Binding ReportItems}" >
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}" />
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
<StackPanel HorizontalAlignment="Left" Height="274" Margin="134,10,0,0" VerticalAlignment="Top" Width="375" DataContext="{Binding SelectedReportItem}">
<StackPanel.Resources>
<Style x:Key="ControlBaseStyle" TargetType="{x:Type Control}">
<Setter Property="Margin" Value="0, 10, 0, 0" />
</Style>
</StackPanel.Resources>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name:"/>
<TextBox Width="150" Text="{Binding Name}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Data File:"/>
<TextBox Width="150" Text="{Binding ID}"/>
</StackPanel>
<DataGrid Height="190" VerticalAlignment="Bottom" ItemsSource="{Binding TItems}"/>
</StackPanel>
<Button x:Name="button_Copy" Content="Save" HorizontalAlignment="Right" Margin="0,0,92,10" VerticalAlignment="Bottom" Width="75"/>
</Grid>
</Window>
My ViewModel:
public class MainViewModel
{
public ObservableCollection<ReportItem> ReportItems { get; set; }
public object SelectedReportItem { get; set; }
public MainViewModel()
{
ReportItems = new ObservableCollection<ReportItem>();
ReportItems.Add(Example);
}
public ReportItem Example = new TextReportItem() { Name = "John", DataFile = "try.txt"};
}
ReportItem:
public class ReportItem
{
public int Id { get; set; }
public string Name { get; set; }
public string DataFile { get; set; }
}
TextReportItem:
public class TextReportItem : ReportItem
{
public ObservableCollection<TextParcel> TItems { get; set; }
}
public class TextParcel
{
char Delimiter { get; set; }
string LineExp { get; set; }
string Result { get; set; }
string IgnoreLine { get; set; }
int DesiredResultIndexInLine { get; set; }
}
EDIT: as I use MVVM, I prefer to use only XAML in the View, with no code behind.
EDIT 2:
Thanks to S.Akbari I succeeded to view the desired properties in the TextBox controls, with the following code:
<StackPanel Orientation="Horizontal">
<TextBlock Text="Name:"/>
<TextBox Width="150" Text="{Binding ElementName=listBox, Path=SelectedItem.Name}"/>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock Text="Data File:"/>
<TextBox Width="150" Text="{Binding ElementName=listBox, Path=SelectedItem.DataFile}"/>
</StackPanel>
But when the same logic is applied to my DataGrid, it fails for some reason:
<DataGrid Height="190" VerticalAlignment="Bottom" ItemsSource="{Binding ElementName=listBox, Path=SelectedItem.TItmes}" />
I also tried:
<DataGrid Height="190" VerticalAlignment="Bottom" DataContext="{Binding ElementName=listBox, Path=SelectedItem}" ItemsSource="{Binding TItems}"/>
And also:
<DataGrid Height="190" VerticalAlignment="Bottom" DataContext="{Binding ElementName=listBox, Path=SelectedItem}">
<DataTemplate>
<TextBlock Text="{Binding TItems}" />
</DataTemplate>
</DataGrid>
if you use MVVM your view model should raise property changed events
You should implement INotifyPropertyChanged
and change the selected item to be a full property
see :How to: Implement Property Change Notification

Dynamic MenuItems with ItemsSource in xaml?

I'm crap atn english, so sorry..
I'm trying to create dynamic menu items that display something based on a collection (a list of object), here is my xaml, you can see the "ListBox" and the "MenuItem".
As I said, I'm binding the header to the "name" of my object :
MainWindow.xaml
<Grid Margin="0,0,-8,-9" Background="Black" >
<DockPanel x:Name="LayoutRoot">
<Grid VerticalAlignment="Top">
<MediaElement x:Name="mediaElement" HorizontalAlignment="Center" Margin="0,0,60,30" VerticalAlignment="Top" MouseLeftButtonUp="mediaElement_MouseLeftButtonUp">
</MediaElement>
<Menu HorizontalAlignment="Left" Height="30" VerticalAlignment="Top" Width="525" IsMainMenu="True">
<MenuItem Header="Menu">
<ListBox x:Name="myList" HorizontalAlignment="Right" VerticalAlignment="Top" Margin="461,-261,-1,106" Background="#FFFFE800" MouseDoubleClick="ListBox_Double_Click" Width="57">
<ListBox.ItemTemplate>
<DataTemplate>
<Grid>
<MenuItem Header="{Binding name}"> </MenuItem>
</Grid>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</MenuItem>
</Menu>
</Grid>
Here is my code in the c#, as you can see I bind "myList" (which is my ListBox) with the ItemsGetSource of list (which contains the things I want to display in my menu):
public MainWindow()
{
var list = new List<History>
{
new History() { name = "Guy1"},
new History() { name = "Guy2"},
new History() { name = "Guy3"},
new History() { name = "Guy4"},
};
InitializeComponent();
this.myList.ItemsSource = list;
}
And my class "History" (the "name" field is what I want to display)
namespace MediaPlayer
{
public class History
{
// "prop" puis "tab"
public String name { get; set; }
public String path { get; set; }
public int time { get; set; }
public override string ToString()
{
return name;
}
}
}
I think I can't use itemSource for my menuItems, maybe?
Here is an example that only uses MenuItems:
MainWindow.xaml
<Grid Margin="0,0,-8,-9" Background="Black" >
<DockPanel x:Name="LayoutRoot">
<Grid VerticalAlignment="Top">
<MediaElement x:Name="mediaElement" HorizontalAlignment="Center" Margin="0,0,60,30" VerticalAlignment="Top" MouseLeftButtonUp="mediaElement_MouseLeftButtonUp">
</MediaElement>
<Menu HorizontalAlignment="Left" Height="30" VerticalAlignment="Top" Width="525" IsMainMenu="True">
<MenuItem Header="Menu" x:Name="myList">
<MenuItem.ItemContainerStyle>
<Style>
<Setter Property="MenuItem.Header" Value="{Binding name}"/>
</Style>
</MenuItem.ItemContainerStyle>
</MenuItem>
</Menu>
</Grid>
</DockPanel>
</Grid>
The result looks like this:

Categories

Resources