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 need help with getting the information in my enum into a combobox.
Here is the code for my enum:
namespace Arsalan_Salam_991571527_A2
{
public enum CarType
{
Odyssey,
Rouge,
Sienna,
Accord
}
}
I have found some code that was suppose to work and I tried to implement into my code to make the information inside of enum appear as shown below:
private void AddingEnumIntoComboBox(Car c)
{
foreach (var item in Enum.GetValues(typeof(CarType)))
{
carTypeInput.Items.Add(item);
}
}
But for some reason the program works fine but this code does not show the information of my enum into the combobox which is called carTypeInput. This is for a college assignment.
Here is the xaml that I used to create the UI interface:
<Page
x:Class="Arsalan_Salam_991571527_A2.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:Arsalan_Salam_991571527_A2"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid RenderTransformOrigin="0.497,0.522">
<TextBlock HorizontalAlignment="Left" Margin="572,10,0,0" Text="DriveWell Inc." TextAlignment="Center" FontSize="50" VerticalAlignment="Top" Width="374" Height="72"/>
<TextBlock HorizontalAlignment="Left" Margin="87,88,0,0" Text="Vin Number" TextAlignment="Center" FontSize="30" VerticalAlignment="Top" Width="192" Height="67" RenderTransformOrigin="0.457,-0.751"/>
<TextBlock HorizontalAlignment="Left" Margin="67,185,0,0" Text="Car Make" TextAlignment="Center" FontSize="30" VerticalAlignment="Top" Width="194" Height="63"/>
<TextBlock HorizontalAlignment="Left" Margin="87,282,0,0" Text="Car Type" TextAlignment="Center" FontSize="30" VerticalAlignment="Top" Width="183" Height="61"/>
<TextBlock HorizontalAlignment="Left" Text="Purchase Price" TextAlignment="Center" FontSize="30" VerticalAlignment="Top" Margin="87,380,0,0" Width="226" Height="61" RenderTransformOrigin="3.948,-0.233"/>
<TextBlock HorizontalAlignment="Left" Margin="87,487,0,0" Text="Model Year" TextAlignment="Center" FontSize="30" VerticalAlignment="Top" Height="65" Width="190" RenderTransformOrigin="3.283,-2.555"/>
<TextBlock HorizontalAlignment="Left" Margin="87,584,0,0" Text="Mileage (Km)" TextAlignment="Center" FontSize="30" VerticalAlignment="Top" Height="43" Width="192"/>
<Button x:Name="addingCar" Click="addingCar_Click" Content="Add Car" FontSize="30" Margin="43,639,0,0" VerticalAlignment="Top" Height="56" Width="156"/>
<Button x:Name="clearing" Click="clearing_Click" Content="Clear" FontSize="30" Margin="224,639,0,0" VerticalAlignment="Top" Height="56" Width="134"/>
<Button x:Name="updatingCar" Click="updatingCar_Click" Content="Update" FontSize="30" Margin="379,639,0,0" VerticalAlignment="Top" Height="56" Width="130"/>
<ComboBox x:Name="carTypeInput" Margin="348,282,0,0" Width="191" Height="57"/>
<ComboBox x:Name="modelYearInput" Margin="348,483,0,0" Width="191" Height="52"/>
<TextBox x:Name="vinNumberInput" HorizontalAlignment="Left" Margin="348,88,0,0" Text="" FontSize="25" VerticalAlignment="Top" Height="40" Width="191" RenderTransformOrigin="0.476,-1.383"/>
<TextBox x:Name="carMakeInput" HorizontalAlignment="Left" Margin="348,185,0,0" Text="" FontSize="25" VerticalAlignment="Top" Height="40" Width="191"/>
<TextBox x:Name="purchasePriceInput" HorizontalAlignment="Left" Margin="348,380,0,0" Text="" FontSize="25" VerticalAlignment="Top" Height="52" Width="191"/>
<TextBox x:Name="mileageInput" HorizontalAlignment="Left" Margin="348,584,0,0" Text="" FontSize="15" VerticalAlignment="Top" Height="32" Width="191"/>
<Image x:Name="carImageOutput" HorizontalAlignment="Left" Height="429" Margin="1013,106,0,0" VerticalAlignment="Top" Width="226"/>
<TextBlock x:Name="errorMessageOutput" HorizontalAlignment="Left" Margin="572,624,0,0" Text="" FontSize="35" VerticalAlignment="Top" Width="641" Height="62"/>
<ListView x:Name="lstCarDetailOutput" Margin="572,88,315,120"></ListView>
</Grid>
</Page>
jdweng pointed this out in their comment, but I'll expand on it and make it an answer:
The problem is that Enum.GetValues returns the values of an enum, which is a integral type (currently C# enums are more or less a fancy wrapper around a bunch of constant numbers). By default this is a int (more here). Meaning your call to Enum.GetValues(typeof(CarType)) is returning int[]. Now there are multiple ways to get the name of an enum value, I'll demonstrate two.
Convert the int back to an enum value and call ToString
foreach (var item in Enum.GetValues(typeof(CarType))
{
// This can be written as 'carTypeInput.Items.Add(((CarType) item).ToString());'
var carType = (CarType) item;
carTypeInput.Items.Add(carType.ToString());
}
Use Enum.GetName to avoid having to get an instance of CarType
foreach (var item in Enum.GetValue(typeof(CarType))
{
// This can be written as 'carTypeInput.Items.Add(Enum.GetName(typeof(CarType), item));
var carTypeName = Enum.GetName(typeof(CarType), item);
carTypeInput.Items.Add(carTypeName);
}
Why not use Enum.GetNames?
private void Form1_Load(object sender, EventArgs e)
{
comboBox1.Items.AddRange(Enum.GetNames(typeof(CarType)));
}
private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
{
string carTypeName = comboBox1.SelectedItem.ToString();
if(carTypeName == CarType.Accord.ToString())
{
...
}
}
I am trying to use a dataGrid in WPF with c#. But I cannot get my datagrid to show any of my data in the table when I run my program in debug mode. I have this code executing when the datagrid loads. But all I see is an empty square.
private void dataGrid1_Loaded(object sender, RoutedEventArgs e)
{
var items = new List<SaveTable>();
items.Add(new SaveTable("A" , 0));
items.Add(new SaveTable("B" , 0));
items.Add(new SaveTable("C" , 0));
items.Add(new SaveTable("D" , 0));
items.Add(new SaveTable("E" , 0));
var grid = sender as DataGrid;
grid.ItemsSource = items;
}
I save a class named SaveTable which looks like this:
class SaveTable
{
public string Name { get; set; }
public double Value { get; set; }
public SaveTable(string name, double value)
{
this.Name = name;
this.Value = value;
}
}
I got this code format online and it seems like everything is right? any suggestions?
here is the xaml code for that window
<Window x:Class="RobustCalculator.Storage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Storage" Height="499" Width="546" Activated="Window_Activated" Loaded="Window_Loaded">
<Grid>
<TextBlock Height="23" HorizontalAlignment="Left" Margin="10,10,0,0" Name="textBlock1" Text="A" VerticalAlignment="Top" />
<TextBox HorizontalAlignment="Left" Margin="24,10,0,306" Name="valueA" Width="120" TextChanged="valueA_TextChanged" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="24,39,0,0" Name="valueB" VerticalAlignment="Top" Width="120" TextChanged="valueB_TextChanged" />
<TextBlock Height="20" HorizontalAlignment="Left" Margin="10,42,0,0" Name="textBlock2" Text="B" VerticalAlignment="Top" Width="20" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="24,71,0,0" Name="valueC" VerticalAlignment="Top" Width="120" TextChanged="valueC_TextChanged" />
<TextBlock Height="23" HorizontalAlignment="Left" Margin="10,72,0,0" Name="textBlock3" Text="C" VerticalAlignment="Top" />
<TextBlock Height="23" HorizontalAlignment="Left" Margin="10,101,0,0" Name="textBlock4" Text="D" VerticalAlignment="Top" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="24,98,0,0" Name="valueD" VerticalAlignment="Top" Width="120" TextChanged="valueD_TextChanged" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="24,130,0,0" Name="valueE" VerticalAlignment="Top" Width="120" TextChanged="valueE_TextChanged" />
<TextBlock Height="23" HorizontalAlignment="Left" Margin="11,131,0,0" Name="textBlock5" Text="E" VerticalAlignment="Top" />
<DataGrid AutoGenerateColumns="False" Height="200" HorizontalAlignment="Left" Margin="235,130,0,0" Name="dataGrid1" VerticalAlignment="Top" Width="200" SelectionChanged="dataGrid1_SelectionChanged" Loaded="dataGrid1_Loaded" />
</Grid>
I added a breakpoint and the code isn't being executed. I am using the Loaded event, should I be using a different event?
Your code works fine with Loaded event but at the moment you set AutoGenerateColumns="False" and don't define columns. You need to either define columns manually
<DataGrid AutoGenerateColumns="False" ... Loaded="dataGrid1_Loaded">
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" Header="Name"/>
<DataGridTextColumn Binding="{Binding Value}" Header="Value"/>
</DataGrid.Columns>
</DataGrid>
or let it auto generate columns
<DataGrid AutoGenerateColumns="True" ... Loaded="dataGrid1_Loaded"/>
So, I've got a UserControl which displays basic information about a customer extracted from a file object.
The control looks like this:
<UserControl x:Class="Ns.Gui.pnlDebtor"
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="230" d:DesignWidth="460" xmlns:my="clr-namespace:Ns.Gui">
<Grid>
<GroupBox Header="Debtor" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="groupBox1" VerticalAlignment="Stretch">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="28" />
<RowDefinition Height="56" />
<RowDefinition Height="28" />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="80*" />
<ColumnDefinition Width="380*" />
</Grid.ColumnDefinitions>
<Label Content="Name:" Height="28" HorizontalAlignment="Left" Name="lblName" VerticalAlignment="Top" />
<Label Content="Address:" Grid.Row="1" Height="28" HorizontalAlignment="Left" Name="lblAddress" VerticalAlignment="Top" />
<Label Content="Customer Nr.:" Grid.Row="2" Height="28" HorizontalAlignment="Left" Name="lblCustomerNr" VerticalAlignment="Top" />
<TextBox Grid.Column="1" Height="23" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="tbName" VerticalAlignment="Top" IsEnabled="False" IsReadOnly="False" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:pnlDebtor, AncestorLevel=1}, Path=DebtorName, Mode=OneWay}" />
<TextBox Grid.Column="1" Grid.Row="1" Height="46" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="tbAddress" VerticalAlignment="Top" IsReadOnly="True" IsEnabled="False" Text="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=my:pnlDebtor, AncestorLevel=1}, Path=Adresse, Mode=OneWay}" />
<TextBox Grid.Column="1" Grid.Row="2" Height="23" HorizontalAlignment="Stretch" Margin="0,0,0,0" Name="tbCustomerNr" VerticalAlignment="Top" IsEnabled="False" IsReadOnly="True" />
<Button Content="Debtor Details" Grid.ColumnSpan="2" Grid.Row="3" Height="23" HorizontalAlignment="Left" Margin="0,0,0,0" Name="btnDetails" VerticalAlignment="Top" />
</Grid>
</GroupBox>
</Grid>
</UserControl>
My Name and Address Textboxes are bound to DebtorName and DebtorAddress properties of the pnlDebtor UserControl.
Codebehind is like so:
public partial class pnlDebtor : UserControl
{
private MyFile file = null;
public MyFile File
{
get
{
return file;
}
set
{
file = value;
tbCustomerNr.Text = file.CustomerNo;
}
}
private Contact debtor = null;
public Contact Debtor
{
get
{
if (debtor == null)
{
if (File != null)
{
debtor = AbstractDataObject.GetObject4ID<Contact>(File.DebtorID);
}
}
return debtor;
}
}
private Address debtorAddress = null;
public string Address
{
get
{
string result = string.Empty;
if (debtorAddress == null)
{
if (Debtor != null)
{
List<Address> lsAddresses = AbstractDataObject.GetObject4NonIdProperty<Address>("ContactID", Debtor.ID);
if (lsAddresses.Any())
{
debtorAddress = lsAddresses[0];
result += lsAddresses[0].Street + "\r\n"
+ lsAddresses[0].PostalCode + " " + lsAddresses[0].City;
}
}
}
else
{
result += debtorAddress.Street + "\r\n"
+ debtorAddress.PostalCode + " " + debtorAddress.City;
}
return result;
}
}
private string strDebtorName = string.Empty;
public string DebtorName
{
get
{
if (strDebtorName== string.Empty)
{
if (Debtor != null)
{
strDebtorName = Debtor.Name1;
if (Debtor.FirstName != null)
strSchuldnerName += ", " + Debtor.FirstName;
}
}
return strDebtorName;
}
}
public pnlDebtor()
{
InitializeComponent();
}
}
As you can see, unlike the Name and Address Textboxes, my CustomerNr Textbox is populated in the codebehind. When I pass in my file object, I extract the customer number and assign that value to the Text property of the appropriate Textbox. Both methods work, but the first method (Binding) seems to be prefered for WPF. Why?
To me, the disadvantages are:
1) Logic and presentation aren't separated. If I send my xaml to someone in design, there's a chance they could screw up my binding.
2) If I'm debugging and set a breakpoint, the Text property of my bound Textboxes is always an empty string. I can't see what's going on.
So, what are the advantages of using binding? Why is it the preferred method? Use small words. This is my first WPF project. :)
I think the missing link here is MVVM. Your bindings to properties in codebehind mean that that particular UserControl is still tightly coupled to that particular class. I wouldn't have said that it's any better than the version without bindings. The codebehind class won't compile unless the XAML page is bundled with it, because there's a reference to tbCustomerNr.Text.
Using MVVM and bindings, the ViewModel is completely isolated from the View. I can, if I like, delete the Views entirely from my program and the ViewModels will still compile without any complaints. This means that the ViewModel logic can be reused easily, and logic and UI development tasks can be separated cleanly.
Please help me with the following code,I want to add a row inputted by user to a gridview.
I am able to add a row but its empty!!Please help.it worked in windows forms but its not working with WPF.
private void button1_Click(object sender, RoutedEventArgs e)
{
GetGridView();
}
private void GetGridView()
{
string[] row0 = {textBox1.Text,"Beatles" };
dataGrid1.Items.Add(row0);
dataGrid1.Columns[0].DisplayIndex = 0;
dataGrid1.Columns[1].DisplayIndex = 1;
}
//////////////
sure,here it is
<Window x:Class="WpfApplication2.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="964">
<Grid>
<DataGrid AutoGenerateColumns="False" Height="274" HorizontalAlignment="Left" Margin="509,12,0,0" Name="dataGrid1" VerticalAlignment="Top" Width="239" DataContext="{Binding}" ItemsSource="{Binding}" ItemStringFormat="{Binding}" SelectedIndex="-1" SelectionChanged="dataGrid1_SelectionChanged">
<DataGrid.Columns>
<DataGridTextColumn Header="Header1" />
<DataGridTextColumn Header="Header" />
</DataGrid.Columns>
</DataGrid>
<TextBox Height="23" HorizontalAlignment="Left" Margin="184,12,0,0" Name="textBox1" VerticalAlignment="Top" Width="120" TextChanged="textBox1_TextChanged" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="184,187,0,0" Name="textBox2" VerticalAlignment="Top" Width="120" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="184,125,0,0" Name="textBox3" VerticalAlignment="Top" Width="120" />
<TextBox Height="23" HorizontalAlignment="Left" Margin="184,66,0,0" Name="textBox4" VerticalAlignment="Top" Width="120" />
<Button Content="Button" Height="23" HorizontalAlignment="Left" Margin="414,231,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
</Grid>
Edit: You bound the ItemsSource of the DataGrid, you cannot add items to the grid itself while that is the case, add the items to the bound collection (which is what i originally suggested)
I would not suggest you do anything like that. In WPF you should bind your controls to the data, that way you can change the source-collection and the grid will get updated automatically, which is less messy than using any method like DataGrid.Items.Add which accepts input of type object.
e.g.
Xaml:
<DataGrid ItemsSource="{Binding GridData}" Name="DGrid"/>
<TextBox Name="TB" Width="100"/>
<Button Content="Add" Click="Button_Click"/>
Code:
private ObservableCollection<Employee> gridData = new ObservableCollection<Employee>();
public ObservableCollection<Employee> GridData
{
get { return gridData; }
}
private void Button_Click(object sender, RoutedEventArgs e)
{
GridData.Add(new Employee(TB.Text, "Beatles?"));
}