i'm trying to learn WPF and on top of that the MVVM style of doing things.
I have a simple practice app in which i would like to display codes in a combo box.
My Code
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace SteamCodes
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
private ObservableCollection<Codes> codes;
public MainWindow()
{
InitializeComponent();
codes = new ObservableCollection<Codes>()
{
new Codes() {CodeID = "1", Code="CODETEXT"}
};
steamCode.ItemsSource = codes.ToString();
}
}
public class Codes
{
public string CodeID { get; set; }
public string Code { get; set; }
}
}
My XAML
<Window x:Class="SteamCodes.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:SteamCodes"
mc:Ignorable="d"
Title="MainWindow" Height="350" Width="525">
<Grid>
<ComboBox x:Name="steamCode" ItemsSource="{Binding Source = Codes}" HorizontalAlignment="Left" Height="43" Margin="122,37,0,0" VerticalAlignment="Top" Width="259"/>
</Grid>
</Window>
At the moment my Combo box is Pulling through as each option in the ComboBox is a letter from the line 'System.Collections.Objectmodel.ObservableCollection`1[SteamCodes.Codes]'
Everyone of those letters is a different drop down option in the combo box.
Any Ideas where i have gone wrong.
Your ComboBox ItemSource must be a collection of items, not a string:
steamCode.ItemsSource = codes;
You also have to specify which property of your item must be considered as value to be shown in combobox by setting DisplayMemberPath property:
steamCode.DisplayMemberPath = "Code";
To specify which property of bound objects will be used as actual selected value you have to use SelectedValuePath property:
steamCode.SelectedValuePath = "CodeID";
The MVVM approach is this:
public class ViewModel
{
public ObservableCollection<Codes> Codes { get; }
= new ObservableCollection<Codes>();
}
The MainWindow constructor:
public MainWindow()
{
InitializeComponent();
var viewModel = new ViewModel();
viewModel.Codes.Add(new Codes { CodeID = "1", Code = "CODETEXT" });
DataContext = viewModel;
}
The XAML:
<ComboBox ItemsSource="{Binding Codes}" DisplayMemberPath="Code" .../>
Related
I have a class that has several properties, one of which is editable, another of which is calculated based on the editable value. I want to initialize the editable value with something and allow the user to change it however they wish. However, I also want to have a reset button that puts the original value back into the textbox. I have a third variable that stores the value of the original number. However, I am not sure how I am supposed to access the object when the reset button is clicked to put the value back into the textbox. I've put the relevant code below (if I shouldn't be posting everything please let me know, still new to stackoverflow how-to):
Main Window
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using HDR_BED_Calc_local.Testers;
using HDR_BED_Calc_local.Helpers;
namespace HDR_BED_Calc_local
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
//var window = new MainWindow();
this.DataContext = new fraction_doses(800, 700, 900, 800, 900, 1, 3);
}
}
}
XAML
<Window x:Class="HDR_BED_Calc_local.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:HDR_BED_Calc_local"
xmlns:uctesters="clr-namespace:HDR_BED_Calc_local.Testers"
mc:Ignorable="d"
Title="MainWindow" Height="450" Width="800">
<Grid>
<uctesters:fx_tester x:Name="fxtester_UC"/>
</Grid>
</Window>
Custom user control
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using HDR_BED_Calc_local.Helpers;
namespace HDR_BED_Calc_local.Testers
{
/// <summary>
/// Interaction logic for fx_tester.xaml
/// </summary>
public partial class fx_tester : UserControl
{
public fx_tester()
{
InitializeComponent();
}
private void Button_Click(object sender, RoutedEventArgs e)
{
// What do I put here??
}
}
}
XAML
<UserControl x:Class="HDR_BED_Calc_local.Testers.fx_tester"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:HDR_BED_Calc_local.Testers"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" Background="White">
<StackPanel HorizontalAlignment="Center">
<StackPanel Orientation="Horizontal">
<TextBlock xml:space="preserve">Fraction: </TextBlock>
<TextBlock Text="{Binding Path=fraction_number}"></TextBlock>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock xml:space="preserve">Current Dose: </TextBlock>
<TextBox x:Name="curr_fx_tb" Text="{Binding Path=editable_fraction_dose, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</StackPanel>
<StackPanel Orientation="Horizontal">
<TextBlock xml:space="preserve">EQD2: </TextBlock>
<TextBlock Text="{Binding Path=this_fx_brachy_EQD2, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
</StackPanel>
<Button Content="Reset" Click="Button_Click"/>
</StackPanel>
</UserControl>
Helper function with class
C#
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.ComponentModel;
using System.Runtime.CompilerServices;
namespace HDR_BED_Calc_local.Helpers
{
internal class fraction_doses : INotifyPropertyChanged
{
public int fraction_number { get; set; }
public double alpha_beta { get; }
private double _editable_fraction_dose;
public double editable_fraction_dose
{
get { return _editable_fraction_dose; }
set
{
_editable_fraction_dose = value;
calc_EQD2();
this.OnPropertyChanged("editable_fraction_dose");
}
}
public double actual_fraction_dose { get; }
public double pear_plan_dose { get; }
public double IMRT_plan_dose { get; }
public double max_dose_limit { get; }
public double preferred_dose_limit { get; }
private double _this_fx_brachy_EQD2;
public double this_fx_brachy_EQD2
{
get { return this._this_fx_brachy_EQD2; }
set
{
this._this_fx_brachy_EQD2 = value;
this.OnPropertyChanged("this_fx_brachy_EQD2");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public fraction_doses(double current_dose, double pear_dose, double IMRT_dose, double max_dose_limit, double preferred_dose_limit, int fraction_number, int alpha_beta)
{
this.alpha_beta = alpha_beta;
this.actual_fraction_dose = current_dose;
this.editable_fraction_dose = current_dose;
this.pear_plan_dose = pear_dose;
this.IMRT_plan_dose = IMRT_dose;
this.max_dose_limit = max_dose_limit;
this.preferred_dose_limit = preferred_dose_limit;
this.fraction_number = fraction_number;
}
public void calc_EQD2()
{
// EQD2 is always reported in Gray even though we will be reporting cGy
double dose_Gy = this.editable_fraction_dose/100;
this.this_fx_brachy_EQD2 = Math.Round(1 * dose_Gy * (1+ dose_Gy / alpha_beta)/(1+2/alpha_beta), 2);
}
public void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
if (PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
You can try the following:
private void Button_Click(object sender, RoutedEventArgs e)
{
// What do I put here??
var dc = (fraction_doses ) this.DataContext:
if(dc!=null)
dc.Clear();
}
in your fraction_doses class add the method that clears the properties
public void Clear(){
this.MyProperty = MY_DEFAULT_VALUE;
//clear other properties..
}
I have made a list that is a property amnd then given that list values and this is still not working to place in a listview as a itemsource i have no idea how to fix this and get results is there anyone that can show me what im doing wrong here? i am placing the data context in the MainWindow
XAML
<Window x:Class="CRM.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:local="clr-namespace:CRM"
mc:Ignorable="d"
Title="MainWindow" Height="1080" Width="1920">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="0*"/>
</Grid.ColumnDefinitions>
<ListView ItemsSource="{Binding tickets}" Margin="0,10,1075,0" MaxWidth="990"/>
</Grid>
</Window>
MainViewModel:
using API.Objects;
using API.ViewModels;
using System;
using System.Collections.Generic;
using System.Text;
namespace API.ViewModels
{
public class MainViewModel : BaseViewModel
{
int Counter{ get; set; }
List<TicketO> tickets { get; set;}
public MainViewModel()
{
TicketO ticket = new TicketO("Jens", "Svensson", "jenson1234#live.se", "0767942768", "This is working but my box is not", 500);
tickets.Add(ticket);
}
}
}
MainWindow
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using API.ViewModels;
namespace CRM
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
this.DataContext = new MainViewModel();
}
}
}
Make tickets public, DataContext = this; is missing, refer below link.
How can I bind a List as ItemSource to ListView in XAML?
I have a simple wpf app, that I want to try to use ItemsSource binding from xaml. When I click the button. it should be updated also in the UI, but it doesn't.
Why doesn't it work?
Xaml code:
<Window x:Class="SendRawEthernetPacketsGUI.Window1"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Window1" Height="300" Width="300">
<Grid>
<ComboBox HorizontalAlignment="Left" Margin="76,65,0,0" VerticalAlignment="Top" Width="120" ItemsSource="{Binding test}"/>
<Button Content="Button" HorizontalAlignment="Left" Margin="90,171,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
</Grid>
C# code:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
namespace SendRawEthernetPacketsGUI
{
/// <summary>
/// Interaction logic for Window1.xaml
/// </summary>
public partial class Window1 : Window
{
public ObservableCollection<string> test = new ObservableCollection<string>();
public Window1()
{
InitializeComponent();
DataContext = this;
}
private void Button_Click(object sender, RoutedEventArgs e)
{
test.Add("fdfddf");
}
}
}
It feels kinda stupid to even ask this, but even looking in google didn't help me. So can you?
Your binding never worked in the first place. You can only bind to properties not fields.
Try this instead:
public ObservableCollection<string> test { get; set; }
public Window1()
{
Test = new ObservableCollection<string>();
}
Or if you want some tricky C# 6 magic:
public ObservableCollection<string> test => new ObservableCollection<string>();
This is a function bodied-member and compiles to a read-only property that is initialized to the new ObservableCollection
Caveats/Design Errors:
Note that in both cases you aren't using INotifyPropertyChanged, so wholesale assignments to the collection won't be picked up by the UI. You should also be using PascalCase for your public properties, and using a proper view model instead of binding to the code-behind.
I've just started working with WPF, and to start with, I'd like to know how to programatically add instances of my own custom class with the one property of 'Name' to a listbox, and the listbox will show each element as its name in the UI, rather than as "MyNamespace.CustomClass".
I've read vague things about DataContexts and DataBinding and DataTemplates, but I want to know the absolute minimum I can do, preferably with as little XAML as possible - I find it fairly bewildering.
Thanks!
I know you want to avoid binding but I'll throw this out there anyway. try not to be too scared of XAML, it's a bit crazy to start with but once you get used to all of the {binding}s it's actually pretty obvious, a simple example of binding a listbox to a collection in code behind would go something like this.
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
DataContext="{Binding RelativeSource={RelativeSource Self}}"
Title="MainWindow" Height="350" Width="525">
<ListBox ItemsSource="{Binding Items}">
<ListBox.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Name}"/>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Window>
The DataContext property in Window tells it where bindings will look by default (which in this case is the window) and the data template tells the list box how to display each item found in the collection.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication1
{
public class MyClass
{
public string Name { get; set; }
}
public partial class MainWindow : Window
{
public ObservableCollection<MyClass> Items
{
get { return (ObservableCollection<MyClass>)GetValue(ItemsProperty); }
set { SetValue(ItemsProperty, value); }
}
public static readonly DependencyProperty ItemsProperty =
DependencyProperty.Register("Items", typeof(ObservableCollection<MyClass>), typeof(MainWindow), new PropertyMetadata(null));
public MainWindow()
{
InitializeComponent();
Items = new ObservableCollection<MyClass>();
Items.Add(new MyClass() { Name = "Item1" });
Items.Add(new MyClass() { Name = "Item2" });
Items.Add(new MyClass() { Name = "Item3" });
Items.Add(new MyClass() { Name = "Item4" });
Items.Add(new MyClass() { Name = "Item5" });
}
}
}
When pasted in to Visual Studio as is the above code should show this.
I have an issue when I try to use datagrid.items.add() to add items from one datagrid to another. Basically I have two data grids acting in a master slave relationship. The First DataGrid1 is used to display automatically generated columns and rows. The second datagrid, DataGrid2 will display the DataGrid1.SelectedItems when a specific button is clicked. Each time the button is clicked I'd like to have the selected items from DataGrid1 stay in DataGrid2 and each time the button is clicked more items get added to DataGrid2. I have been able to complete most of my requirements with the exception of the ability to edit cells on DataGrid2. When I double click a cell in DataGrid2 I get an exception that says "EditItem' is not allowed for this view". I have read a lot of posts about adding data to a ObservableCollection, ListCollectionView and so on but either I can not implement them in the correct manner or there not working for my situation. My code is as follows and by the way thx in advance
<Window x:Class="WpfApplication1.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid AutoGenerateColumns="False" Height="77" HorizontalAlignment="Left" Margin="27,12,0,0" Name="dataGrid1" VerticalAlignment="Top" Width="464" />
<Button Content="AddRow" Height="23" HorizontalAlignment="Left" Margin="27,107,0,0" Name="button1" VerticalAlignment="Top" Width="75" Click="button1_Click" />
<DataGrid AutoGenerateColumns="False" Height="140" HorizontalAlignment="Left" Margin="27,159,0,0" Name="dataGrid2" VerticalAlignment="Top" Width="464" />
</Grid>
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace WpfApplication1
{
///
/// Interaction logic for MainWindow.xaml
///
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
dataGrid1.ItemsSource = idata;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
foreach (latlongobj item in dataGrid1.SelectedItems)
{
dataGrid2.Items.Add(item);
}
}
}
}
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace WpfApplication1
{
class latlonobj
{
public string name { get; set; }
public double Lat { get; set; }
public double Lon { get; set; }
}
}
Is this what you want?
public partial class MainWindow : Window
{
ObservableCollection dataGrid2Items = new ObservableCollection();
public MainWindow()
{
InitializeComponent();
dataGrid1.ItemsSource = idata;
dataGrid2.ItemsSource = dataGrid2Items;
}
private void button1_Click(object sender, RoutedEventArgs e)
{
foreach (latlongobj item in dataGrid1.SelectedItems)
{
if( !dataGrid2Items.Contains( item ) )
dataGrid2Items.Add(item);
}
}
private ObservableCollection<latlongobj> idata = new ObservableCollection<latlongobj>
{
new latlongobj{ name = "n1", Lat = 1, Lon = 2 },
new latlongobj{ name = "n2", Lat = 2, Lon = 3 },
new latlongobj{ name = "n3", Lat = 4, Lon = 5 },
};