I'm trying to update the controls present on my Main Window based on the listviewitem selected by the user, but when the listviewitem selection is changed the controls do not update.
I used this post as reference How to dynamically change a WPF control's template using a checkbox?
EDIT: I initially used ContentTemplate but changed this to DataTemplate based on suggestions, however it still is not updating
The XMAL for my Main Window is
<Window.Resources>
<DataTemplate x:Key="Default">
<Grid Margin="20,280,0,0" />
</DataTemplate>
<DataTemplate x:Key="ERAFileSelect">
<Border BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Left" Height="218" Margin="20,280,0,0" VerticalAlignment="Top" Width="257" CornerRadius="15">
<Grid Name="grdFileSelect">
<Label x:Name="lblProcessContent" Content="Drag File or Manually Select File" HorizontalAlignment="Center" VerticalAlignment="Top" Width="257" HorizontalContentAlignment="Center"/>
<TextBox x:Name="txtEraFileName" HorizontalAlignment="Left" Height="23" Margin="10,80,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="235"/>
<Button x:Name="btnSelectFiles" Content="Manually Select File(s)" HorizontalAlignment="Left" Margin="10,161,0,0" VerticalAlignment="Top" Width="235" Height="45"/>
</Grid>
</Border>
</DataTemplate>
<DataTemplate x:Key="FCSFileSelect">
<Border BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Left" Height="218" Margin="20,280,0,0" VerticalAlignment="Top" Width="257" CornerRadius="15">
<Grid Name="grdFileSelect">
<Label x:Name="lblProcessContent" Content="Drag File or Manually Select Files" HorizontalAlignment="Center" VerticalAlignment="Top" Width="257" HorizontalContentAlignment="Center"/>
<TextBox x:Name="txtFCSFileName_TQ02" HorizontalAlignment="Left" Height="23" Margin="10,40,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="174"/>
<Button x:Name="btnSelectFiles_TQ02" Content="Select" HorizontalAlignment="Left" Margin="189,37,0,0" VerticalAlignment="Top" Width="56" Height="28"/>
<TextBox x:Name="txtFCSFileName_TQ11" HorizontalAlignment="Left" Height="23" Margin="10,105,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="174"/>
<Button x:Name="btnSelectFiles_TQ11" Content="Selec" HorizontalAlignment="Left" Margin="189,100,0,0" VerticalAlignment="Top" Width="56" Height="28"/>
<TextBox x:Name="txtFCSFileName_TQ16" HorizontalAlignment="Left" Height="23" Margin="10,170,0,0" TextWrapping="Wrap" Text="TextBox" VerticalAlignment="Top" Width="174"/>
<Button x:Name="btnSelectFiles_TQ16" Content="Select" HorizontalAlignment="Left" Margin="189,165,0,0" VerticalAlignment="Top" Width="56" Height="28"/>
</Grid>
</Border>
</DataTemplate>
</Window.Resources>
<Grid Margin="0,0,2,0">
<GroupBox x:Name="gbxProgress" Header="Progress" HorizontalAlignment="Left" Margin="298,105,0,0" VerticalAlignment="Top" Height="445" Width="462" Foreground="Black">
<ListBox x:Name="lbxProgress" HorizontalAlignment="Left" Height="408" Margin="10,10,0,0" VerticalAlignment="Top" Width="431" Foreground="Black" IsSynchronizedWithCurrentItem="True" ItemsSource="{Binding Progress.Message}" />
</GroupBox>
<Button x:Name="btnStart" Content="Start" HorizontalAlignment="Left" Margin="20,513,0,0" VerticalAlignment="Top" Width="100" Height="37" IsEnabled="{Binding Properties.StartButtonEnabled}" Click="btnStart_Click"/>
<Button x:Name="btnCancel" Content="Cancel" HorizontalAlignment="Left" Margin="177,513,0,0" VerticalAlignment="Top" Width="100" Height="37"/>
<Border BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Left" Height="70" Margin="20,21,0,0" VerticalAlignment="Top" Width="740" CornerRadius="15">
<Grid>
<Image HorizontalAlignment ="Left" Margin="10" Height="50" Width="50" VerticalAlignment="Center" Source="/Lib/Icons/User.png" />
<TextBlock Name="txtUser" FontSize="20" Height="30" Width="200" Foreground="Red" HorizontalAlignment="Left" Margin="78,19,0,19"/>
<Image HorizontalAlignment ="Left" Margin="443,8,0,10" Height="50" Width="50" VerticalAlignment="Center" Source="Lib/Icons/Watch.png" />
<TextBlock x:Name="txtRunTime" FontSize="20" Height="30" Width="200" Foreground="Red" HorizontalAlignment="Left" Margin="519,19,0,19" Text="{Binding AppRunTime.TimeElapsed}" />
</Grid>
</Border>
<Border BorderBrush="Black" BorderThickness="1" HorizontalAlignment="Left" Height="144" Margin="20,119,0,0" VerticalAlignment="Top" Width="257" CornerRadius="15">
<Grid>
<Label x:Name="lblProcessSelection" Content="Process Selection" HorizontalAlignment="Center" VerticalAlignment="Top" Width="257" HorizontalContentAlignment="Center"/>
<ListView x:Name="lvProcessSelection" HorizontalAlignment="Left" Height="93" Margin="10,30,0,0" VerticalAlignment="Top" Width="235" BorderThickness="0" SelectionChanged="lvProcessSelection_SelectionChanged">
<ListViewItem Name="itmERA" Content="Expense Reserve Automation"/>
<ListViewItem Name="itmFCS" Content="Financial Close Status"/>
<ListViewItem Name="itmPEL" Content="Peel"/>
</ListView>
</Grid>
</Border>
<ContentControl DataContext="{Binding Properties}" Content="{Binding}">
<ContentControl.Style>
<Style TargetType="ContentControl">
<Setter Property="ContentTemplate" Value="{StaticResource ERAFileSelect}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding SelectedProcess}" Value="Expense Reserve Automation">
<Setter Property="ContentTemplate" Value="{StaticResource ERAFileSelect}" />
</DataTrigger>
<DataTrigger Binding="{Binding SelectedProcess}" Value="Financial Close Status">
<Setter Property="ContentTemplate" Value="{StaticResource FCSFileSelect}" />
</DataTrigger>
</Style.Triggers>
</Style>
</ContentControl.Style>
</ContentControl>
</Grid>
ViewModel Code is
public class MainWindowModel
{
public ApplicationRunTime AppRunTime { get; set; }
public LogMessage Progress { get; set; }
public MainWindowProperties Properties { get; set; }
public MainWindowModel()
{
AppRunTime = new ApplicationRunTime();
Progress = new LogMessage();
Properties = new MainWindowProperties();
Properties.StartButtonEnabled = false;
}
}
With the MainWindowProperties class
public class MainWindowProperties
{
public bool StartButtonEnabled { get; set; }
public string SelectedProcess { get; set; }
}
And within my MainWindow Constructor I have set the DataContext
mainWindowModel = new MainWindowModel();
this.DataContext = mainWindowModel;
When the selection from lvProcessSelection is changed the following code is executed
if (lvProcessSelection.SelectedItems.Count > 0)
{
mainWindowModel.Properties.SelectedProcess = ((ListViewItem)lvProcessSelection.SelectedItem).Content.ToString();
}
else
{
mainWindowModel.Properties.SelectedProcess = string.Empty;
}
This will update SelectedProcess within my ViewModel with either "Expense Reserve Automation" or "Financial Close Status"
I know the DataContext is set correctly for my ViewModel (but may not be for the ContentControl) as I am able to update lbxProgress with new messages and update txtRunTime with the application RunTime
However when I change the selection on lvProcessSelection nothing happens; the default controls of ERAFileSelect remains.
Could anybody point me in the right direction on how to solve this?
Could anybody point me in the right direction on how to solve this?
Your MainWindowProperties class should implement the INotifyPropertyChanged interface and raise change notifications whenever the SelectedProcess property is set to a new value:
public class MainWindowProperties : INotifyPropertyChanged
{
public bool StartButtonEnabled { get; set; }
private string _selectedProcess;
public string SelectedProcess
{
get { return _selectedProcess; }
set { _selectedProcess = value; NotifyPropertyChanged(); }
}
public event PropertyChangedEventHandler PropertyChanged;
private void NotifyPropertyChanged([CallerMemberName] String propertyName = "")
{
if (PropertyChanged != null)
PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
Please refer to MSDN for more information about this common interface: https://msdn.microsoft.com/en-us/library/system.componentmodel.inotifypropertychanged(v=vs.110).aspx
Every view model/model that you bind to must implement this interface and raise change notifications for any target value in the view to be updated.
Why you are not using Data template? Data template will work in this scenario.
Related
I have a list of objects in my mainViewmodel. When selecting in the listbox, depending on the selected type, a groupbox for this type should be visible and the properties should be binded.
I am not sure how i can achive this. I tried some stuff but i dont get it worked.
Foreach type of the ISimulator i have a groupbox and when I select it in the listbox, i try to show the right groupbox and bind the properties to that.
Thanks in advance
Xaml:
<Window x:Class="ControlCenter.Simulators.Gui.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"
DataContext="MainViewModel"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="1000">
<Grid x:Name="MainGrid" Margin="10,0,0,0" >
<Button Content="Add Simulator" HorizontalAlignment="Left" Margin="44,34,0,0" VerticalAlignment="Top" Width="88" />
<GroupBox x:Name="gb_Vehicle" Header="{Binding SimulatorId}" Margin="177,0,10,0" Visibility="Hidden">
<Grid Height="402" Margin="10,0,12,0">
<Label Content="StartCoordinates(x,y)" HorizontalAlignment="Left" Margin="21,21,0,0" VerticalAlignment="Top"/>
<Label x:Name="tb_Radius_Header" Content="Radius" HorizontalAlignment="Left" VerticalAlignment="Top" Width="126" Margin="21,91,0,0"/>
<Label x:Name="tb_Freq_Header" Content="Frequency" HorizontalAlignment="Left" VerticalAlignment="Top" Width="120" Margin="21,159,0,0"/>
<Label x:Name="tb_DeltaT_Header" Content="Delta T" HorizontalAlignment="Left" VerticalAlignment="Top" Margin="21,213,0,0"/>
<Label x:Name="tb_Velocity_Header" Content="Velocity" HorizontalAlignment="Left" Margin="21,278,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="tb_Cord_X" HorizontalAlignment="Left" Margin="30,52,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="51" Text="{Binding SelectedItem.XCord, ElementName=lb_Vehicles,Mode=TwoWay ,ValidatesOnDataErrors=True , UpdateSourceTrigger=PropertyChanged}"/>
<TextBox x:Name="tb_Cord_Y" HorizontalAlignment="Left" Margin="96,52,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="51" Text="{Binding SelectedItem.YCord, ElementName=lb_Vehicles,Mode=TwoWay ,ValidatesOnDataErrors=True , UpdateSourceTrigger=PropertyChanged}"/>
<TextBox x:Name="tb_Radius" HorizontalAlignment="Left" Margin="30,122,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="52" Text="{Binding SelectedItem.Radius, ElementName=lb_Vehicles,Mode=TwoWay ,ValidatesOnDataErrors=True , UpdateSourceTrigger=PropertyChanged}" />
<TextBox x:Name="tb_DealtaT" HorizontalAlignment="Left" Margin="30,244,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Text="{Binding SelectedItem.DeltaT, ElementName=lb_Vehicles,Mode=TwoWay ,ValidatesOnDataErrors=True , UpdateSourceTrigger=PropertyChanged}"/>
<TextBox x:Name="tb_Freq" HorizontalAlignment="Left" Margin="30,183,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Text="{Binding SelectedItem.Frequency, ElementName=lb_Vehicles,Mode=TwoWay ,ValidatesOnDataErrors=True , UpdateSourceTrigger=PropertyChanged}"/>
<TextBox x:Name="tb_Velocity" HorizontalAlignment="Left" Margin="30,309,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Text="{Binding SelectedItem.Velocity, ElementName=lb_Vehicles, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged, ValidatesOnDataErrors=True}"/>
<WpfPlot Name="Plot" Margin="292,2,10,-2"/>
<Button x:Name="bt_Start" Content="Start" HorizontalAlignment="Left" Margin="21,366,0,0" VerticalAlignment="Top" Width="91" Height="26" />
<Button x:Name="bt_pos" Content="Draw" HorizontalAlignment="Left" Margin="134,366,0,0" VerticalAlignment="Top" Height="26" Width="77" />
</Grid>
</GroupBox>
<GroupBox x:Name="gb_Traffic" Header="{Binding SimulatorId}" Margin="177,0,10,0" Visibility="Hidden">
<Grid>
<ComboBox HorizontalAlignment="Left" Margin="27,57,0,0" VerticalAlignment="Top" Width="120"/>
<Label Content="Traffic Light Type" HorizontalAlignment="Left" Margin="27,10,0,0" VerticalAlignment="Top" Width="120"/>
<Label Content="Position (x,y)" HorizontalAlignment="Left" Margin="27,107,0,0" VerticalAlignment="Top" Width="120"/>
<TextBox x:Name="tb_Traffic_X" HorizontalAlignment="Left" Margin="27,162,0,0" TextWrapping="Wrap" Text="x" VerticalAlignment="Top" Width="60"/>
<TextBox x:Name="tb_Traffic_Y" HorizontalAlignment="Left" Margin="27,196,0,0" TextWrapping="Wrap" Text="y" VerticalAlignment="Top" Width="60"/>
<Label Content="PhasePlan" HorizontalAlignment="Left" Margin="220,55,0,0" VerticalAlignment="Top" Width="92"/>
<ListView d:ItemsSource="{d:SampleData ItemCount=5}" Margin="220,86,10,127">
<ListView.Resources>
<Style TargetType="{x:Type GridViewColumnHeader}">
<Setter Property="HorizontalContentAlignment" Value="Left" />
</Style>
</ListView.Resources>
<ListView.View>
<GridView>
<GridViewColumn Header="OrderId" />
<GridViewColumn Header="Color"/>
<GridViewColumn Header="TotalDuration"/>
<GridViewColumn Header="BlinkDuration"/>
<GridViewColumn Header="Action"/>
</GridView>
</ListView.View>
</ListView>
<Button x:Name="bt_LoadConfig" Content="Load Config" HorizontalAlignment="Left" Margin="524,13,0,0" VerticalAlignment="Top" RenderTransformOrigin="0.044,-0.116" Width="107"/>
<GroupBox Header="New Phase" Margin="10,313,189,20">
<Grid>
<Label Content="Color" HorizontalAlignment="Left" Margin="10,6,0,35" Height="30" Width="73"/>
<Label Content="Total Duration" HorizontalAlignment="Left" Margin="176,10,0,31" Height="30" Width="110"/>
<Label Content="Blink Duration" HorizontalAlignment="Left" Margin="341,7,0,34" Height="30" Width="110"/>
<ComboBox x:Name="cb_TrafficColor" HorizontalAlignment="Left" Margin="10,36,0,0" VerticalAlignment="Top" Width="120"/>
<TextBox x:Name="tb_TotalDuration" HorizontalAlignment="Left" Margin="176,38,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<TextBox x:Name="tb_BlinkDuration" HorizontalAlignment="Left" Margin="341,39,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
<Button x:Name="bt_AddPhase" Content="Add" HorizontalAlignment="Left" Margin="489,37,0,0" VerticalAlignment="Top" Width="62"/>
</Grid>
</GroupBox>
<Button x:Name="bt_SaveConfig" Content="Save Config" HorizontalAlignment="Left" Margin="651,13,0,0" VerticalAlignment="Top" RenderTransformOrigin="0.044,-0.116" Width="107"/>
<Button x:Name="bt_StartTraffic" Content="Start" HorizontalAlignment="Left" Margin="669,397,0,0" VerticalAlignment="Top" Width="89"/>
</Grid>
</GroupBox>
<GroupBox x:Name="gb_AddSimulator" Header="Add Simulator" Margin="190,0,0,0" Visibility="Visible">
<Grid Margin="10,0,21,0">
<Label x:Name="tb_ObjectId_Header" Content="ObjectId" HorizontalAlignment="Left" Margin="241,29,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="tb_ObjectId" HorizontalAlignment="Left" Margin="222,66,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Text="{Binding Path=SimulatorModel.Config.ObjectID, Mode=TwoWay ,ValidatesOnDataErrors=True , UpdateSourceTrigger=PropertyChanged}"/>
<Label x:Name="tb_IPAdress_Header" Content="IPAdress" HorizontalAlignment="Left" Margin="54,84,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="tb_IPAdress" HorizontalAlignment="Left" Margin="54,115,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Text="{Binding Path=SimulatorModel.Config.IpAddress, Mode=TwoWay ,ValidatesOnDataErrors=True , UpdateSourceTrigger=PropertyChanged}"/>
<Label x:Name="tb_PortTCP_Header" Content="Port TCP" HorizontalAlignment="Left" Margin="236,84,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="tb_PortUDP" HorizontalAlignment="Left" Margin="55,169,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Text="{Binding Path=SimulatorModel.Config.PortUDP, Mode=TwoWay ,ValidatesOnDataErrors=True , UpdateSourceTrigger=PropertyChanged}"/>
<TextBox x:Name="tb_PortTCP" HorizontalAlignment="Left" Margin="222,115,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Text="{Binding Path=SimulatorModel.Config.PortTCP, Mode=TwoWay ,ValidatesOnDataErrors=True , UpdateSourceTrigger=PropertyChanged}"/>
<Label x:Name="tb_PortGrpc_Header_" Content="Port GRPC" HorizontalAlignment="Left" Margin="236,138,0,0" VerticalAlignment="Top"/>
<TextBox x:Name="tb_PortGrpc" HorizontalAlignment="Left" Margin="222,169,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120" Text="{Binding Path=SimulatorModel.Config.PortGRPC, Mode=TwoWay ,ValidatesOnDataErrors=True, UpdateSourceTrigger=PropertyChanged}"/>
<Label x:Name="tb_PortUDP_Header1" Content="Port UDP" HorizontalAlignment="Left" Margin="57,138,0,0" VerticalAlignment="Top"/>
<Button x:Name="bt_Add" Content="Add" HorizontalAlignment="Left" Margin="144,240,0,0" VerticalAlignment="Top" Width="119" Command="{Binding AddSimulatorCommand}" />
<ComboBox x:Name="cb_SimulatorType" HorizontalAlignment="Left" Margin="54,64,0,0" VerticalAlignment="Top" Width="120"/>
<Label x:Name="tb_PortGrpc_Header__Copy" Content="Simulator Type" HorizontalAlignment="Left" Margin="57,29,0,0" VerticalAlignment="Top"/>
</Grid>
</GroupBox>
<ListBox x:Name="lb_Simulators" d:ItemsSource="{Binding }" Margin="0,94,818,10"/>
</Grid>
</Window>
MainWindow.cs:
public partial class MainWindow : Window
{
private ILogger _logger;
public MainWindow()
{
InitializeComponent();
var mainViewModel = new MainViewModel(_logger);
this.DataContext = mainViewModel;
mainViewModel.SimulatorModels = new List<SimulatorModel>()
{
new SimulatorModel("1", null, null),
new SimulatorModel("2", null, null),
new SimulatorModel("3", null, null),
};
//lb_Simulators.ItemsSource = mainViewModel.SimulatorModels;
//lb_Simulators.DisplayMemberPath = "ID";
//gb_AddSimulator.DataContext = mainViewModel.SimulatorModel.Config;
//_logger.Information("Gui startet");
}
private void SetGroupBox(GroupBoxNames name, ISimulator simulator)
{
gb_Vehicle.Visibility = Visibility.Hidden;
gb_Traffic.Visibility = Visibility.Hidden;
gb_AddSimulator.Visibility = Visibility.Hidden;
switch (name)
{
case GroupBoxNames.AddSimulator:
gb_AddSimulator.Visibility = Visibility.Visible;
break;
case GroupBoxNames.Traffic:
gb_Traffic.Visibility = Visibility.Visible;
gb_Traffic.DataContext = simulator;
break;
case GroupBoxNames.Vehicle:
gb_Vehicle.Visibility = Visibility.Visible;
gb_Vehicle.DataContext = simulator;
break;
default:
break;
}
}
MainViewModel:
private ILogger _logger;
public IList<SimulatorModel> SimulatorModels { get; set; }
public SimulatorModel SimulatorModel { get; set; }
public ISimulator Simulator { get; set; }
public ICommand AddSimulatorCommand;
public ICommand RemoveSimulatorCommand;
public ICommand LoadSimulatorConfigCommand;
public ICommand SaveSimulatorConfigCommand;
public ICommand AddPhaseCommand;
public ICommand AddStartSimulatorCommand;
public bool CanStart { get; private set; } = true;
public event PropertyChangedEventHandler? PropertyChanged;
SimulatorModel:
public class SimulatorModel
{
public string ID { get; set; }
public SimulatorConfigModel Config { get; set; }
public ISimulator Simulator { get; set; }
public SimulatorModel(string id,SimulatorConfigModel configModel, ISimulator simulator)
{
ID = id;
Config = configModel;
Simulator = simulator;
}
}
Whenever you need dynamic data type based views you usually have to define a DataTemplate for each. Using the DataTemplate makes manual control of the GroupBox.Visibility obsolete and significantly reduces lines of code related to the related logic. See Microsoft Docs: Data Templating Overview
The following example shows how to display a dedicated GroupBox based on three imaginary ISimulator implementations: SimulatorA, SimulatorB and SimulatorC.
The associated GroupBox itself is hosted in a DataTemplate - one for each ISimulator implementation.
A ContentControl is used to render the DataTemplate. ContentControl.Comtent is bound to the SimulatorModel.Simulator property i.e. the ISimulator instance of the currently selected item of the ListBox:
<Window>
<Window.Resources>
<DataTemplate DataType="{x:Type SimulatorA}">
<GroupBox x:Name="gb_Vehicle">
...
</GroupBox>
</DataTemplate>
<DataTemplate DataType="{x:Type SimulatorB}">
<GroupBox x:Name="gb_Traffic">
...
</GroupBox>
</DataTemplate>
<DataTemplate DataType="{x:Type SimulatorC}">
<GroupBox x:Name="gb_AddSimulator">
...
</GroupBox>
</DataTemplate>
</Window.Resources>
<StackPanel>
<ListBox x:Name="SimulatorList"
ItemsSource="{Binding SimulatorModels}" />
<!-- Host for the GroupBox that is rendered via DataTemplate
based on the SimulatorModel.Simulator property.
Instead of binding directly to the ListBox.SelectedItem like below,
you can bind to a MainViewModel.SelectedSimulatorModel property, which is bound to the ListBox.SelectedItem -->
<ContenControl Content="{Binding ElementName=SimulatorList, Path=SelectedItem.Simulator}" />
</StackPanel>
</Window>
You should bind the ListBox, or XAML elements in general, rather than assigning values explicitly in code-behind. Especially in an MVVM scenario where you always focus on the data models rather than on the view's elements: you only update the data model and let the framework take care of the GUI via data binding. If you have to update the source collection dynamically, make the source collection e.g., SimulatorModels of type ObservableCollectio<T>.
I've got one page in my WPF app that should display some "tiles" in number as I specify before. Tile looks like this:
So my page should look something like this:
It is achievable of course by manually cloning tiles, but I want to avoid this (achieve it in more programmatic way). So instead of creating 6 clones I should stick to only one and then if needed add remaining ones. How can I accomplish that? I guess I should create my own UserControl like this:
<Grid HorizontalAlignment="Left" Height="199" VerticalAlignment="Top" Width="207" Background="Black">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="0*"/>
</Grid.RowDefinitions>
<Image x:Name="image1" HorizontalAlignment="Left" Height="175" VerticalAlignment="Top" Width="207" Stretch="UniformToFill"/>
<Grid HorizontalAlignment="Left" Height="30" VerticalAlignment="Top" Width="112" Background="#FFC78D10">
<TextBox IsReadOnly = "True" x:Name="CategoryOfEvent" Height="30" TextWrapping="Wrap" Text="Category" Width="112" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="White" FontSize="18" SelectionBrush="{x:Null}" HorizontalAlignment="Left" VerticalAlignment="Top" >
<TextBox.Template>
<ControlTemplate TargetType="{x:Type TextBox}">
<ScrollViewer Name="PART_ContentHost"/>
</ControlTemplate>
</TextBox.Template>
</TextBox>
</Grid>
<TextBox IsReadOnly = "True" x:Name="HourOfEvent" HorizontalAlignment="Left" Height="28" Margin="0,42,0,0" TextWrapping="Wrap" Text="Hour" VerticalAlignment="Top" Width="148" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="#FFE2E2E2" FontSize="22" SelectionBrush="{x:Null}" FontWeight="Bold" TextChanged="HourOfEvent_TextChanged">
<TextBox.Template>
<ControlTemplate TargetType="{x:Type TextBox}">
<ScrollViewer Name="PART_ContentHost"/>
</ControlTemplate>
</TextBox.Template>
</TextBox>
<TextBox IsReadOnly = "True" x:Name="TitleOfEvent" HorizontalAlignment="Left" Height="88" Margin="0,82,0,0" TextWrapping="Wrap" Text="Title" VerticalAlignment="Top" Width="207" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="White" FontSize="20" SelectionBrush="{x:Null}" FontWeight="Bold">
<TextBox.Template>
<ControlTemplate TargetType="{x:Type TextBox}">
<ScrollViewer Name="PART_ContentHost"/>
</ControlTemplate>
</TextBox.Template>
</TextBox>
<TextBox IsReadOnly = "True" x:Name="PlaceOfEvent" HorizontalAlignment="Left" Height="24" Margin="0,175,0,0" TextWrapping="Wrap" Text="Where" VerticalAlignment="Top" Width="207" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="White" FontSize="14" SelectionBrush="{x:Null}">
<TextBox.Template>
<ControlTemplate TargetType="{x:Type TextBox}">
<ScrollViewer Name="PART_ContentHost"/>
</ControlTemplate>
</TextBox.Template>
</TextBox>
</Grid>
and just add them to my page. I would like also to mention that in every tiles there are 4 textboxes which are displaying some data parsed from Json, so maybe some automatic binding should do the job?
It is as simple as that.Firstly,what you can do is,create a UserControl with all your controls inside like TextBlocks and others.Then,decide which type of container control you want to use to hold your UserControl.Let's assume it's a grid.You can specify/set grid's column/rows for each user control.A sample :
private void addControl()
{
UserControl1 MyCon = new UserControl1;
MyGrid.Children.Add(MyCon);
Grid.SetRow(MyCon , 1); ////replace 1 with required row count
}
You can create grid rows in design time,or u can do it in code behind as well :
MyGrid.RowDefinitions.Add(new RowDefinition);
If you want to use columns instead,just apply same code but change Row/Rowdefinition with Column/ColumnDefinition
Hope this helps :)
The follwing example shows how to create multiple of the tiles you have been posting using a DataTemplate and WrapPanel. The DataTemplate specifies how an object (in this case a TileItem) is visualized. You can create multiple TileItems and then add them to an collection, in order to visualize them all.
Assuming your UI resides in MainWindow, you can create a collection with three items in it.
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
TileItemCollection = new ObservableCollection<TileItem>(new []
{
new TileItem(){Category = "Alpha", Hour = "10", Title = "Hello World", Where = "Office"},
new TileItem(){Category = "Beta", Hour = "15", Title = "Test", Where = "Home"},
new TileItem(){Category = "Gamma", Hour = "44", Title = "My Title", Where = "Work"},
});
DataContext = this;
}
public ObservableCollection<TileItem> TileItemCollection { get; }
}
You could load your Items from JSON and create an TileItem for each one in the JSON document. The class for TileItemss can be found below.
public class TileItem : INotifyPropertyChanged
{
private string _hour;
private string _title;
private string _where;
private string _category;
public string Category
{
get => _category;
set
{
if (value == _category) return;
_category = value;
OnPropertyChanged();
}
}
public string Hour
{
get => _hour;
set
{
if (value == _hour) return;
_hour = value;
OnPropertyChanged();
}
}
public string Title
{
get => _title;
set
{
if (value == _title) return;
_title = value;
OnPropertyChanged();
}
}
public string Where
{
get => _where;
set
{
if (value == _where) return;
_where = value;
OnPropertyChanged();
}
}
public event PropertyChangedEventHandler PropertyChanged;
[NotifyPropertyChangedInvocator]
protected virtual void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
Note that in order for datachanges to be propagated to the UI, all properties which should be updated in the UI when you update them in code need to raise the property changed event. In this example all properties do this by default.
You can then update the XAML to bind to a collection. The ItemsControl acts as a container for the tiles. If you scroll down further you may notice the use of WrapPanel which is responsible for the item wrapping effect when you resize the control.
<ItemsControl ItemsSource="{Binding TileItemCollection}" Margin="20">
<ItemsControl.ItemTemplate>
<DataTemplate DataType="{x:Type local:TileItem}" >
<Grid HorizontalAlignment="Left" Height="199" VerticalAlignment="Top" Width="207" Background="Black">
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="0*"/>
</Grid.RowDefinitions>
<Image x:Name="image1" HorizontalAlignment="Left" Height="175" VerticalAlignment="Top" Width="207" Stretch="UniformToFill"/>
<Grid HorizontalAlignment="Left" Height="30" VerticalAlignment="Top" Width="112" Background="#FFC78D10">
<TextBox IsReadOnly="True" Height="30" TextWrapping="Wrap" Text="{Binding Path=Category}" Width="112" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="White" FontSize="18" SelectionBrush="{x:Null}" HorizontalAlignment="Left" VerticalAlignment="Top" >
<TextBox.Template>
<ControlTemplate TargetType="{x:Type TextBox}">
<ScrollViewer Name="PART_ContentHost"/>
</ControlTemplate>
</TextBox.Template>
</TextBox>
</Grid>
<TextBox IsReadOnly="True" HorizontalAlignment="Left" Height="28" Margin="0,42,0,0" TextWrapping="Wrap" Text="{Binding Path=Hour}" VerticalAlignment="Top" Width="148" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="#FFE2E2E2" FontSize="22" SelectionBrush="{x:Null}" FontWeight="Bold">
<TextBox.Template>
<ControlTemplate TargetType="{x:Type TextBox}">
<ScrollViewer Name="PART_ContentHost"/>
</ControlTemplate>
</TextBox.Template>
</TextBox>
<TextBox IsReadOnly="True" HorizontalAlignment="Left" Height="88" Margin="0,82,0,0" TextWrapping="Wrap" Text="{Binding Path=Title}" VerticalAlignment="Top" Width="207" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="White" FontSize="20" SelectionBrush="{x:Null}" FontWeight="Bold">
<TextBox.Template>
<ControlTemplate TargetType="{x:Type TextBox}">
<ScrollViewer Name="PART_ContentHost"/>
</ControlTemplate>
</TextBox.Template>
</TextBox>
<TextBox IsReadOnly="True" x:Name="PlaceOfEvent" HorizontalAlignment="Left" Height="24" Margin="0,175,0,0" TextWrapping="Wrap" Text="{Binding Path=Where}" VerticalAlignment="Top" Width="207" Background="{x:Null}" BorderBrush="{x:Null}" Foreground="White" FontSize="14" SelectionBrush="{x:Null}">
<TextBox.Template>
<ControlTemplate TargetType="{x:Type TextBox}">
<ScrollViewer Name="PART_ContentHost"/>
</ControlTemplate>
</TextBox.Template>
</TextBox>
</Grid>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<WrapPanel/>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.Template>
<ControlTemplate>
<ScrollViewer>
<ItemsPresenter />
</ScrollViewer>
</ControlTemplate>
</ItemsControl.Template>
</ItemsControl>
Each Tile is bound to an TileItem which means that the Bindings which point to e.g. Category, point to the Category of an TileItem.
To increase reusability it would be possible to move the code into its own usercontrol and optionally to add DependencyPropertys for better control.
I have listview with binding:
<ListView x:Name="OrdersListView" IsItemClickEnabled="True" SelectionMode="Single"
ItemClick="OrdersListView_ItemClick" SelectedItem="{Binding AllRoundsSelectedItem, Mode=TwoWay}">
I need to click element and receive data.
I do it like this.
public RootObject allRoundsSelectedItem;
public RootObject AllRoundsSelectedItem
{
get { return allRoundsSelectedItem; }
set { allRoundsSelectedItem = value; OnPropertyChanged();}
}
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void OrdersListView_ItemClick(object sender, ItemClickEventArgs e)
{
}
When i set breakpoint on this row set { allRoundsSelectedItem = value; OnPropertyChanged();}
I see that I have value that I need to have.
I try to enter data in another ListView.
Here code for it:
<ScrollViewer HorizontalAlignment="Left" Height="667" Margin="415,54,-124,-1" VerticalAlignment="Top" Width="989">
<ListView x:Name="DetailsListView" ItemsSource="{Binding AllRoundsSelectedItem}">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel Height="667" Width="989">
<Grid x:Name="DetailGrid" Height="667" Width="989" VerticalAlignment="Top" >
<Grid HorizontalAlignment="Left" Height="44" VerticalAlignment="Top" Width="989" BorderBrush="#FFFBF8F8" BorderThickness="0,0,1,1">
<TextBlock x:Name="textBlock1" HorizontalAlignment="Left" TextWrapping="Wrap" Text="Время и дата заказа" VerticalAlignment="Top" Height="44" Width="214" FontSize="23"/>
<TextBlock x:Name="textBlock2" HorizontalAlignment="Left" Margin="500,0,0,0" TextWrapping="Wrap" Text="{Binding date_created}" VerticalAlignment="Top" Height="44" Width="360"/>
</Grid>
<Grid HorizontalAlignment="Left" Height="44" Margin="0,44,0,0" VerticalAlignment="Top" Width="989" BorderBrush="#FFFBF8F8" BorderThickness="0,0,1,1">
<TextBlock x:Name="textBlock3" HorizontalAlignment="Left" TextWrapping="Wrap" Text="Статус" VerticalAlignment="Top" Height="44" Width="360" FontSize="23"/>
<TextBlock x:Name="textBlock4" HorizontalAlignment="Left" Margin="500,0,0,0" TextWrapping="Wrap" Text="{Binding status }" VerticalAlignment="Top" Height="44" Width="360"/>
</Grid>
<Grid HorizontalAlignment="Left" Height="44" Margin="0,88,0,0" VerticalAlignment="Top" Width="989" BorderBrush="#FFFBF8F8" BorderThickness="0,0,1,1">
<TextBlock x:Name="textBlock5" HorizontalAlignment="Left" TextWrapping="Wrap" Text="Осталось времени" VerticalAlignment="Top" Height="44" Width="360" FontSize="23"/>
<TextBlock x:Name="textBlock6" HorizontalAlignment="Left" Margin="500,0,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Height="44" Width="360"/>
</Grid>
<Grid HorizontalAlignment="Left" Height="44" Margin="0,132,0,0" VerticalAlignment="Top" Width="989" BorderBrush="#FFFBF8F8" BorderThickness="0,0,1,1">
<TextBlock x:Name="textBlock7" HorizontalAlignment="Left" TextWrapping="Wrap" Text="На когда" VerticalAlignment="Top" Height="44" Width="360" FontSize="23"/>
<TextBlock x:Name="textBlock8" HorizontalAlignment="Left" Margin="500,0,0,0" TextWrapping="Wrap" Text="{Binding billing.city}" VerticalAlignment="Top" Height="44" Width="360"/>
</Grid>
<Grid HorizontalAlignment="Left" Height="44" Margin="0,176,0,0" VerticalAlignment="Top" Width="989" BorderBrush="#FFFBF8F8" BorderThickness="0,0,1,1">
<TextBlock x:Name="textBlock9" HorizontalAlignment="Left" TextWrapping="Wrap" Text="Сумма" VerticalAlignment="Top" Height="44" Width="360" FontSize="23"/>
<TextBlock x:Name="textBlock10" HorizontalAlignment="Left" Margin="500,0,0,0" TextWrapping="Wrap" Text="{Binding total}" VerticalAlignment="Top" Height="44" Width="360"/>
</Grid>
<Grid HorizontalAlignment="Left" Height="44" Margin="0,220,0,0" VerticalAlignment="Top" Width="989" BorderBrush="#FFFBF8F8" BorderThickness="0,0,1,1">
<TextBlock x:Name="textBlock11" HorizontalAlignment="Left" TextWrapping="Wrap" Text="Имя" VerticalAlignment="Top" Height="44" Width="360" FontSize="23"/>
<TextBlock x:Name="textBlock12" HorizontalAlignment="Left" Margin="500,0,0,0" TextWrapping="Wrap" Text="{Binding billing.first_name}" VerticalAlignment="Top" Height="44" Width="360"/>
</Grid>
<Grid HorizontalAlignment="Left" Height="44" Margin="0,264,0,0" VerticalAlignment="Top" Width="989" BorderBrush="#FFFBF8F8" BorderThickness="0,0,1,1">
<TextBlock x:Name="textBlock13" HorizontalAlignment="Left" TextWrapping="Wrap" Text="Телефон" VerticalAlignment="Top" Height="44" Width="360" FontSize="23"/>
<TextBlock x:Name="textBlock14" HorizontalAlignment="Left" Margin="500,0,0,0" TextWrapping="Wrap" Text="{Binding billing.phone}" VerticalAlignment="Top" Height="44" Width="360"/>
</Grid>
<Grid HorizontalAlignment="Left" Height="44" Margin="0,308,0,0" VerticalAlignment="Top" Width="989" BorderBrush="#FFFBF8F8" BorderThickness="0,0,1,1">
<TextBlock x:Name="textBlock15" HorizontalAlignment="Left" TextWrapping="Wrap" Text="Адрес" VerticalAlignment="Top" Height="44" Width="360" FontSize="23"/>
<TextBlock x:Name="textBlock16" HorizontalAlignment="Left" Margin="500,0,0,0" TextWrapping="Wrap" Text="{Binding billing.address_1}" VerticalAlignment="Top" Height="44" Width="360"/>
</Grid>
<Grid HorizontalAlignment="Left" Height="44" Margin="0,352,0,0" VerticalAlignment="Top" Width="989" BorderBrush="#FFFBF8F8" BorderThickness="0,0,1,1">
<TextBlock x:Name="textBlock17" HorizontalAlignment="Left" TextWrapping="Wrap" Text="Количество персон" VerticalAlignment="Top" Height="44" Width="360" FontSize="23"/>
<TextBlock x:Name="textBlock18" HorizontalAlignment="Left" Margin="500,0,0,0" TextWrapping="Wrap" Text="{Binding billing.postcode}" VerticalAlignment="Top" Height="44" Width="360"/>
</Grid>
<Grid HorizontalAlignment="Left" Height="44" Margin="0,396,0,0" VerticalAlignment="Top" Width="989" BorderBrush="#FFFBF8F8" BorderThickness="0,0,1,1">
<TextBlock x:Name="textBlock19" HorizontalAlignment="Left" TextWrapping="Wrap" Text="Откуда" VerticalAlignment="Top" Height="44" Width="360" FontSize="23"/>
<TextBlock x:Name="textBlock20" HorizontalAlignment="Left" Margin="500,0,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Height="44" Width="360"/>
</Grid>
<Grid HorizontalAlignment="Left" Height="44" Margin="0,440,0,0" VerticalAlignment="Top" Width="989" BorderBrush="#FFFBF8F8" BorderThickness="0,0,1,1">
<TextBlock x:Name="textBlock21" HorizontalAlignment="Left" TextWrapping="Wrap" Text="Состав заказа" VerticalAlignment="Top" Height="44" Width="360" FontSize="23"/>
<TextBlock x:Name="textBlock22" HorizontalAlignment="Left" Margin="500,0,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Height="44" Width="360"/>
</Grid>
<Grid HorizontalAlignment="Left" Height="44" Margin="0,484,0,0" VerticalAlignment="Top" Width="989" BorderBrush="#FFFBF8F8" BorderThickness="0,0,1,1">
<TextBlock x:Name="textBlock23" HorizontalAlignment="Left" TextWrapping="Wrap" Text="Приметка для кухни" VerticalAlignment="Top" Height="44" Width="360" FontSize="23"/>
<TextBlock x:Name="textBlock24" HorizontalAlignment="Left" Margin="500,0,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Height="44" Width="360"/>
</Grid>
<Grid HorizontalAlignment="Left" Height="44" Margin="0,528,0,0" VerticalAlignment="Top" Width="989" BorderBrush="#FFFBF8F8" BorderThickness="0,0,1,1">
<TextBlock x:Name="textBlock25" HorizontalAlignment="Left" TextWrapping="Wrap" Text="Приметка для курьера" VerticalAlignment="Top" Height="44" Width="360" FontSize="23"/>
<TextBlock x:Name="textBlock26" HorizontalAlignment="Left" Margin="500,0,0,0" TextWrapping="Wrap" Text="" VerticalAlignment="Top" Height="44" Width="360"/>
</Grid>
</Grid>
</StackPanel></DataTemplate></ListView.ItemTemplate></ListView>
But anything shows.
Where is my trouble?
Thank's for help so much!
Your question wasn't very clear, so I can only guess as to what you were trying to achieve. It looks as though you want some kind of master-detail interface, wherein you choose an item from the list (master) and then another form displays with controls for editing the data for that item (detail).
Your first ListView looks fine (and the binding works as you said). But why are you using another ListView for displaying the details of the selected item? ListViews are for displaying lists of data, but it appears that RootObject is not an array or collection class (I could be wrong, I don't know the class definition). You probably shouldn't be using a ListView, but whatever you use, you should bind the AllRoundsSelectedItem to the DataSource property of the panel.
Solution 1: I mostly agree with #Decade Moon, but for the last line, there is no DataSource property of the StackPanel you used, I think this maybe is a typo, it should be DataContext. Anyway, here I'm writing this answer to give a demo for this solution:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ListView x:Name="OrdersListView" IsItemClickEnabled="True" SelectionMode="Single"
ItemClick="OrdersListView_ItemClick" SelectedItem="{Binding AllRoundsSelectedItem, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ItemName}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ScrollViewer Grid.Column="1">
<StackPanel x:Name="Detail" Grid.Column="1" >
<TextBlock Text="{Binding ItemName}" FontSize="30" Foreground="Red" />
<TextBlock Text="{Binding Paramether1}" Margin="0,15" FontSize="20" />
<TextBlock Text="{Binding Paramether2}" FontSize="20" />
<TextBlock Text="{Binding Paramether3}" Margin="0,15" FontSize="20" />
<TextBlock Text="{Binding Paramether4}" FontSize="20" />
<TextBlock Text="{Binding Paramether5}" Margin="0,15" FontSize="20" />
</StackPanel>
</ScrollViewer>
</Grid>
If your layout is like this, then you can keep your most of the code in behind and in the OrdersListView_ItemClick event code like this:
private void OrdersListView_ItemClick(object sender, ItemClickEventArgs e)
{
AllRoundsSelectedItem = e.ClickedItem as RootObject;
Detail.DataContext = AllRoundsSelectedItem;
}
Solution 2: if you still want to use a ListView to show the details so can they be selected or something else, you can for example code like this:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ListView x:Name="OrdersListView" IsItemClickEnabled="True" SelectionMode="Single"
ItemClick="OrdersListView_ItemClick" SelectedItem="{Binding AllRoundsSelectedItem, Mode=TwoWay}">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding ItemName}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<ListView x:Name="DetailsListView" ItemsSource="{Binding AllRoundsSelectedItem}" Grid.Column="1">
<ListView.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding}" FontSize="20" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
And the type of AllRoundsSelectedItem should be List or OberservableCollection, it means you need to modify your code behind for example like this:
public sealed partial class MainPage : Page, INotifyPropertyChanged
{
public MainPage ()
{
this.InitializeComponent();
this.DataContext = this;
}
private ObservableCollection<RootObject> collection = new ObservableCollection<RootObject>();
protected override void OnNavigatedTo(NavigationEventArgs e)
{
for (int i = 0; i < 100; i++)
{
collection.Add(new RootObject
{
ItemName = "Item " + i,
Paramether1 = "Paramether1 " + i,
Paramether2 = "Paramether2 " + i,
Paramether3 = "Paramether3 " + i,
Paramether4 = "Paramether4 " + i,
Paramether5 = "Paramether5 " + i,
});
}
OrdersListView.ItemsSource = collection;
}
public ObservableCollection<string> allRoundsSelectedItem;
public event PropertyChangedEventHandler PropertyChanged;
public ObservableCollection<string> AllRoundsSelectedItem
{
get { return allRoundsSelectedItem; }
set
{
allRoundsSelectedItem = value;
OnPropertyChanged();
}
}
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
var handler = PropertyChanged;
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
private void OrdersListView_ItemClick(object sender, ItemClickEventArgs e)
{
var item = e.ClickedItem as RootObject;
AllRoundsSelectedItem = new ObservableCollection<string>
{
item.ItemName,item.Paramether1,
item.Paramether2, item.Paramether3,
item.Paramether4, item.Paramether5,
};
}
}
By my side the RootObject class is like this:
public class RootObject
{
public string ItemName { get; set; }
public string Paramether1 { get; set; }
public string Paramether2 { get; set; }
public string Paramether3 { get; set; }
public string Paramether4 { get; set; }
public string Paramether5 { get; set; }
}
There are maybe other solutions, but you will need either modify your xaml code or the data type of your AllRoundsSelectedItem.
I'm working on a WIN 8.1 App. In my App I have a ListView where I'm binding a observable collection from a ViewModel. So far everything works fine. The Problem is, that in the Background all the Data will be loaded correctly, but my ListView displays after approximately 40 elements, from the beginning... In the Background the right Object is selected and 80 Objects are loaded.
Could it be a Problem with the Scrolling?
Does anyone know, how to solve this issue?
From an other Page, i navigate to the Page with the ListView:
private void ShowReturnData()
{
ReturnViewModel retVM = new ReturnViewModel(_navigationService, SelectedTour);
_navigationService.NavigateTo(ViewModelLocator.ReturnPageKey, retVM);
}
In my ViewModel Constructor, I add my data to the observable Collection:
I'm working with MVVMlight.
Properties (ObservableCollection, SelectedItem):
--> observable Collection
/// <summary>
/// The <see cref="Data" /> property's name.
/// </summary>
public const string DataPropertyName = "Data";
private ObservableCollection<ReturnData> _myProperty = new ObservableCollection<ReturnData>();
/// <summary>
/// Sets and gets the Data property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public ObservableCollection<ReturnData> Data
{
get
{
return _myProperty;
}
set
{
if (_myProperty == value)
{
return;
}
_myProperty = value;
RaisePropertyChanged(DataPropertyName);
}
}
--> SelectedItem
/// <summary>
/// The <see cref="SelectedItem" /> property's name.
/// </summary>
public const string SelectedItemPropertyName = "SelectedItem";
private ReturnData _selectedItem = null;
/// <summary>
/// Sets and gets the SelectedTour property.
/// Changes to that property's value raise the PropertyChanged event.
/// </summary>
public ReturnData SelectedItem
{
get
{
return _selectedItem;
}
set
{
if (_selectedItem == value)
{
return;
}
if (_selectedItem != null)
{
_selectedItem.IsFirstItem = false;
_selectedItem.IsLastItem = false;
}
_selectedItem = value;
if (_selectedItem != null)
{
setIsFirstOrLastItem(Data.IndexOf(_selectedItem));
}
RaisePropertyChanged(SelectedItemPropertyName);
}
}
ViewModel Constructor:
public ReturnViewModel(INavigationService navigationService, TourDetailData tourDetails)
{
//Services
_navigationService = navigationService;
//Commands
PrevPageCommand = new RelayCommand(GoToPrevPage);
TourDetails = tourDetails;
TourCustomerName = "Tour " + tourDetails.Tour + " > " + tourDetails.AccountName;
Data = new ObservableCollection<ReturnData>(from i in TourDetails.ReturnData orderby Convert.ToInt32(i.ItemId) select i);
}
XAML:
<ListView x:Name="lvItems"
Grid.Row="2"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
ItemTemplate="{StaticResource ReturnDataTemplate}"
ItemContainerStyle="{StaticResource ReturnDataListViewItemStyle}"
ItemsSource="{Binding Data}"
Margin="0,5,0,0"
Loaded="lvItems_Loaded">
</ListView>
DataTemplate:
<DataTemplate x:Key="ReturnDataTemplate">
<Grid x:Name="grid" d:DesignWidth="1344.53" d:DesignHeight="123.228">
<Grid.Resources>
<converter:SelectionConverter x:Key="SelectionConverter" Context="{Binding}" />
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="20"/>
<ColumnDefinition Width="450*"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="100"/>
</Grid.ColumnDefinitions>
<Rectangle Grid.Row="0" Grid.ColumnSpan="5" Height="100" Fill="LightGray" Visibility="Collapsed"/>
<Rectangle Grid.Row="2" Grid.ColumnSpan="5" Height="100" Fill="LightGray" Visibility="Collapsed"/>
<!--<Rectangle Grid.Row="0" Grid.ColumnSpan="5" Height="100" Fill="LightGray" Visibility="{Binding IsFirstItem, Converter={StaticResource BoolToVisibilityConverter}}"/>
<Rectangle Grid.Row="2" Grid.ColumnSpan="5" Height="100" Fill="LightGray" Visibility="{Binding IsLastItem, Converter={StaticResource BoolToVisibilityConverter}}"/>-->
<Rectangle Grid.Row="1" Fill="{StaticResource OrangeHighlight}" Visibility="{Binding IsDirty, Converter={StaticResource BoolToVisibilityConverter}}"/>
<StackPanel Grid.Row="1" Grid.Column="1" VerticalAlignment="Center" Margin="15,0">
<TextBlock TextWrapping="Wrap" FontSize="42.667" FontFamily="Segoe UI" Text="{Binding ItemId}" FontWeight="SemiBold"/>
<TextBlock TextWrapping="Wrap" Text="{Binding ItemName}" FontSize="32" FontFamily="Segoe UI"/>
</StackPanel>
<!--<TextBox x:Name="tbxReturn" Grid.Row="1" TextWrapping="Wrap" Grid.Column="2" FontFamily="Segoe UI" FontSize="42.667" Text="{Binding Return}" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{StaticResource TextBoxStyleValues}" PreventKeyboardDisplayOnProgrammaticFocus="True" DoubleTapped="tbxReturn_DoubleTapped" GotFocus="tbxReturn_GotFocus" />-->
<TextBox x:Name="tbxReturn" Grid.Row="1" TextWrapping="Wrap" Grid.Column="2" FontFamily="Segoe UI" FontSize="42.667" Text="{Binding Return}" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{StaticResource TextBoxStyleValues}" DoubleTapped="tbxReturn_DoubleTapped" GotFocus="tbxReturn_GotFocus" InputScope="CurrencyAmountAndSymbol" Foreground="#FF520164" />
<TextBox x:Name="tbxMold" Grid.Row="1" TextWrapping="Wrap" Text="{Binding Mildew}" Grid.Column="3" FontFamily="Segoe UI" FontSize="42.667" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{StaticResource TextBoxStyleValues}" DoubleTapped="tbxMold_DoubleTapped" Tapped="tbxMold_Tapped" GotFocus="tbxMold_GotFocus" InputScope="CurrencyAmountAndSymbol" Foreground="#FF019E90" />
<TextBox x:Name="tbxCredit" Grid.Row="1" TextWrapping="Wrap" Text="{Binding Credit}" Grid.Column="4" FontFamily="Segoe UI" FontSize="42.667" HorizontalAlignment="Center" VerticalAlignment="Center" Style="{StaticResource TextBoxStyleValues}" DoubleTapped="tbxCredit_DoubleTapped" Tapped="tbxCredit_Tapped" GotFocus="tbxCredit_GotFocus" InputScope="CurrencyAmountAndSymbol" Foreground="#FF005C9C" />
<!--<Button Grid.Row="1" Content="+" HorizontalAlignment="Stretch" VerticalAlignment="Top" Grid.Column="2" Height="100" Margin="0,-100,0,0" FontSize="48" Style="{StaticResource NumUpDownButtonStyle}" Visibility="{Binding ElementName=lvItems, Path=DataContext.SelectedItem, ConverterParameter=Selected, Converter={StaticResource SelectionConverter}}" Command="{Binding DataContext.IncreaseReturnCommand, ElementName=lvItems}" Opacity="0.9"/>
<Button Grid.Row="1" Content="-" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Grid.Column="2" Margin="0,0,0,-100" Height="100" FontSize="48" Style="{StaticResource NumUpDownButtonStyle}" Visibility="{Binding ElementName=lvItems, Path=DataContext.SelectedItem, ConverterParameter=Selected, Converter={StaticResource SelectionConverter}}" Command="{Binding DataContext.DecreaseReturnCommand, ElementName=lvItems}" Opacity="0.9"/>
<Button Grid.Row="1" Content="+" HorizontalAlignment="Stretch" VerticalAlignment="Top" Grid.Column="3" Height="100" Margin="0,-100,0,0" FontSize="48" Style="{StaticResource NumUpDownButtonStyle}" Visibility="{Binding ElementName=lvItems, Path=DataContext.SelectedItem, ConverterParameter=Selected, Converter={StaticResource SelectionConverter}}" Command="{Binding DataContext.IncreaseMildewCommand, ElementName=lvItems}" Opacity="0.9"/>
<Button Grid.Row="1" Content="-" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Grid.Column="3" Margin="0,0,0,-100" Height="100" FontSize="48" Style="{StaticResource NumUpDownButtonStyle}" Visibility="{Binding ElementName=lvItems, Path=DataContext.SelectedItem, ConverterParameter=Selected, Converter={StaticResource SelectionConverter}}" Command="{Binding DataContext.DecreaseMildewCommand, ElementName=lvItems}" Opacity="0.9"/>
<Button Grid.Row="1" Content="+" HorizontalAlignment="Stretch" VerticalAlignment="Top" Grid.Column="4" Height="100" Margin="0,-100,0,0" FontSize="48" Style="{StaticResource NumUpDownButtonStyle}" Visibility="{Binding ElementName=lvItems, Path=DataContext.SelectedItem, ConverterParameter=Selected, Converter={StaticResource SelectionConverter}}" Command="{Binding DataContext.IncreaseCreditCommand, ElementName=lvItems}" Opacity="0.9"/>
<Button Grid.Row="1" Content="-" HorizontalAlignment="Stretch" VerticalAlignment="Bottom" Grid.Column="4" Margin="0,0,0,-100" Height="100" FontSize="48" Style="{StaticResource NumUpDownButtonStyle}" Visibility="{Binding ElementName=lvItems, Path=DataContext.SelectedItem, ConverterParameter=Selected, Converter={StaticResource SelectionConverter}}" Command="{Binding DataContext.DecreaseCreditCommand, ElementName=lvItems}" Opacity="0.9"/>-->
</Grid>
</DataTemplate>
Style:
<Style x:Key="ReturnDataListViewItemStyle" TargetType="ListViewItem">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<ListViewItemPresenter x:Name="listViewItemPresenter" d:DesignWidth="938.908" d:DesignHeight="103.083"
ContentMargin="0"
DragOpacity="{ThemeResource ListViewItemDragThemeOpacity}"
DisabledOpacity="{ThemeResource ListViewItemDisabledThemeOpacity}"
HorizontalContentAlignment="Stretch"
Padding="0"
PointerOverBackgroundMargin="1"
ReorderHintOffset="{ThemeResource ListViewItemReorderHintThemeOffset}"
SelectionCheckMarkVisualEnabled="False"
SelectedBorderThickness="0"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Margin="15,0,0,0"
SelectedForeground="Black"
SelectedPointerOverBackground="{StaticResource OrangeBackground}"
SelectedPointerOverBorderBrush="{StaticResource OrangeBackground}"
SelectedBackground="{StaticResource OrangeBackground}"
DataContext="{Binding SelectedItem}"
Content="{Binding Mode=OneWay}"
ContentTransitions="{TemplateBinding ContentTransitions}"
PlaceholderBackground="{StaticResource BackgroundGray}">
</ListViewItemPresenter>
</ControlTemplate>
</Setter.Value>
</Setter>
<!--<Setter Property="ContentTemplate" Value="{StaticResource ReturnDataTemplate}"/>-->
</Style>
In the Code behind of the XAML Page, I added the behavior of the ScrollViewer:
private void lvItems_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
SetScrollViewer();
}
private async void SetScrollViewer()
{
if (lvItems.SelectedItem == null)
return;
var item = lvItems.SelectedItem;
var listViewItem = (FrameworkElement)lvItems.ContainerFromItem(item);
if (listViewItem == null)
{
lvItems.ScrollIntoView(item);
}
while (listViewItem == null)
{
await Task.Delay(1);
listViewItem = (FrameworkElement)lvItems.ContainerFromItem(item);
}
var topLeft =
listViewItem
.TransformToVisual(lvItems)
.TransformPoint(new Point()).Y;
var lvih = listViewItem.ActualHeight;
var lvh = lvItems.ActualHeight;
var desiredTopLeft = (lvh - lvih) / 2.0;
var desiredDelta = topLeft - desiredTopLeft;
// Calculations relative to the ScrollViewer within the ListView
var scrollViewer = lvItems.GetFirstDescendantOfType<ScrollViewer>();
var currentOffset = scrollViewer.VerticalOffset;
var desiredOffset = currentOffset + desiredDelta;
//scrollViewer.ScrollToVerticalOffset(desiredOffset);
// better yet if building for Windows 8.1 to make the scrolling smoother use:
scrollViewer.ChangeView(null, desiredOffset, null);
}
Here is my setup, it seems I am not binding the data correctly. The outcome should be a Button with an Image and text displayed. Nothing is displayed.
<UserControl x:Class="AmebaPrototype.UI.LandingPivot.featureControl"
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"
d:DesignHeight="330" d:DesignWidth="960"
DataContext="{Binding Source={StaticResource viewModelLocator}, Path=VideoViewModel}"
>
<UserControl.Resources >
<DataTemplate x:Key="custTemplate" >
<StackPanel >
<Image Source="{Binding ImagePath}"/>
<TextBlock Text="{Binding MyTitle}"/>
</StackPanel>
</DataTemplate>
</UserControl.Resources>
<Grid x:Name="LayoutRoot" Background="{x:Null}" >
<Button Content="Button" Height="316"
HorizontalAlignment="Left" Margin="12,2,0,0"
Name="button1" VerticalAlignment="Top"
Width="423" Click="button1_Click"
ContentTemplate="{DynamicResource custTemplate}"
/>
<Button Content="Button" Height="156" HorizontalAlignment="Left" Margin="441,2,0,0" Name="button2" VerticalAlignment="Top" Width="208" Click="button2_Click" />
<Button Content="Button" Height="156" HorizontalAlignment="Left" Margin="669,2,0,0" Name="button3" VerticalAlignment="Top" Width="208" />
<Button Content="Button" Height="156" HorizontalAlignment="Left" Margin="441,162,0,0" Name="button4" VerticalAlignment="Top" Width="208" />
<Button Content="Button" Height="156" HorizontalAlignment="Left" Margin="669,162,0,0" Name="button5" VerticalAlignment="Top" Width="208" />
</Grid>
Model:
public class Video
{
public string MyTitle { get; set; }
public string ImagePath { get; set; }
}
ViewModel
public ViewModel VideoViewModel
{
get
{
if(viewmodel == null)
{
viewmodel = new ViewModel();
viewmodel.ListData.Clear();
viewmodel.ListData.Add(new Video { MyTitle = "Title1", ImagePath = "exampleimage.com/image.png" });
viewmodel.ListData.Add(new Video { MyTitle = "Title2", ImagePath = "exampleimage.com/image.png" });
}
return viewmodel;
}
}
If you really want to do this using a DataTemplate, then:
<Button>
<Button.Content>
<x:Type TypeName="Visual"/>
</Button.Content>
<Button.Template>
<ControlTemplate TargetType="{x:Type Button}">
<Grid>
<ContentPresenter ContentSource="Content"/>
</Grid>
</ControlTemplate>
</Button.Template>
<Button.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding Path=Name}"/>
</DataTemplate>
</Button.ContentTemplate>
</Button>
Your ViewModel binding should be okay to use here so in the DataTemplate you can just tweak it to include your Image and TextBlock.
DataTemplate in resources:
<DataTemplate x:Key="bTemplate">
<Button Label="{Binding MyTitle}"
Command="{Binding Execute}">
<Image Source="{Binding ImagePath}" />
</Button>
</DataTemplate>
Not exactly as in your question but then you can use a control that takes an ItemSource such as a ListView:
<ListView
ItemsSource="{Binding ListData}"
ItemTemplate="{StaticResource bTemplate}"
>
</ListView>
I added a Command , since it is necessary if you want to implement MVVM rather than event click.