I am new to c# and wpf.
Im my project I am trying to create a new tabs/ remove tab dynamically using button click.
But I am not successfull.
Kindly suggest where I am wrong.
I have taken help from here
https://www.technical-recipes.com/2017/adding-tab-items-dynamically-in-wpf/
I did DataBinding using command for Add/Remove of tab.
I have other .cs files similar as mentioned above. Hence not copy-pasting them here.
Below is my code:
MainWindow.xaml
<Window x:Class="UI_1.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:UI_1"
mc:Ignorable="d"
Title="MainWindow" Height="650" Width="758">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" MinHeight="20.8"/>
<RowDefinition Height="Auto" MinHeight="118.4"/>
<RowDefinition MinHeight="118.4" Height="228"/>
<RowDefinition />
<RowDefinition Height="13*" />
</Grid.RowDefinitions>
<Menu Grid.Row="0" Margin="0,0,-0.4,118.2" Grid.RowSpan="2" >
<MenuItem Header="File">
<MenuItem Header="Open Log File" />
<MenuItem Header="Open Workspace" />
<Separator />
<MenuItem Header="Save as Workspace" />
<MenuItem Header="Set Path host file" />
</MenuItem>
<MenuItem Header="Control">
<MenuItem Header="Open Command Line View" />
</MenuItem>
</Menu>
<WrapPanel Grid.Row="1" Grid.RowSpan="2" Margin="0,0.2,-0.4,0.2" >
<WrapPanel.Resources>
<Style TargetType="Grid">
<Setter Property="Margin" Value="3"/>
</Style>
</WrapPanel.Resources>
<Border BorderBrush="Black" BorderThickness="1" Grid.Column="0">
<Grid Width="180">
<Grid.Resources>
<Style TargetType="Button">
<Setter Property="Margin" Value="1"/>
</Style>
<Style TargetType="TextBlock">
<Setter Property="Margin" Value="3"/>
</Style>
<Style TargetType="TextBox">
<Setter Property="Margin" Value="3"/>
</Style>
</Grid.Resources>
<TextBlock Grid.Column="0" Grid.ColumnSpan="4" VerticalAlignment="Center" Text="Connect To" Margin="3,6,2.8,6" />
<TextBlock Grid.Row="1" Grid.ColumnSpan="4" VerticalAlignment="Center" Text="Log Cmd" Margin="3,8,2.8,8" />
<TextBox Grid.Column="3" Grid.ColumnSpan="3" Text="IP/HostName" Margin="32,3,3.2,3"/>
<ComboBox
x:Name="Job" Grid.Row = "1" Grid.Column="3" Grid.ColumnSpan="3" Margin="32,3,42.2,6">
<ComboBoxItem Content="Trace"/>
<ComboBoxItem Content="List"/>
<ComboBoxItem Content="Dump"/>
<ComboBoxItem Content="Off"/>
<ComboBoxItem Content="On"/>
</ComboBox>
<TextBox Grid.Column="5" Grid.Row = "1" Text="Line" Margin="6.4,3,2.2,6"/>
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10*" />
<ColumnDefinition Width="6*"/>
<ColumnDefinition Width="27*"/>
<ColumnDefinition Width="45*" />
<ColumnDefinition Width="45*" />
<ColumnDefinition Width="46*" />
</Grid.ColumnDefinitions>
</Grid>
</Border>
<GridSplitter Width="2"></GridSplitter>
<Border BorderBrush="Black" BorderThickness="1" >
<Grid Grid.Column="1" Width="120">
<Grid.Resources>
<Style TargetType="Button">
<Setter Property="Margin" Value="2"/>
</Style>
</Grid.Resources>
<Button Content="Play" Margin="2,5,2.2,2"
Command="{Binding x.AddItem}"/>
<Button Content="Stop" Grid.Column="1" Margin="2,5,2.2,2"
Command="{Binding x.RemoveTab}"/>
<Button Content="Send" Grid.ColumnSpan="2" Grid.Row="1" />
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition />
<ColumnDefinition />
</Grid.ColumnDefinitions>
</Grid>
</Border>
<Border BorderBrush="Black" BorderThickness="1" Height="456" Grid.Row="3" >
<TabControl x:Name="tabControl1" HorizontalAlignment="Stretch" MinHeight="50" Margin="0,0.2" Width="736"
ItemsSource="{Binding Titles, Mode=TwoWay}">
<TabControl.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Header}"/>
</DataTemplate>
</TabControl.ItemTemplate>
<TabControl.ContentTemplate>
<DataTemplate>
<TextBlock Text="{Binding Content}"/>
</DataTemplate>
</TabControl.ContentTemplate>
</TabControl>
</Border>
</WrapPanel>
</Grid>
</Window>
MainWindow.XAML.cs
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
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 UI_1
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
class MainWindowVM : INotifyPropertyChanged
{
public class Item
{
public string Header { get; set; }
public string Content { get; set; }
}
public ObservableCollection<Item> Titles
{
get { return _titles; }
set
{
_titles = value;
OnPropertyChanged("Titles");
}
}
static int tabs = 1;
private ObservableCollection<Item> _titles;
private ICommand _addTab;
private ICommand _removeTab;
public ICommand AddTab
{
get
{
return _addTab ?? (_addTab = new TabRelayCommand(
x =>
{
AddTabItem();
}));
}
}
public ICommand RemoveTab
{
get
{
return _removeTab ?? (_removeTab = new TabRelayCommand(
x =>
{
RemoveTabItem();
}));
}
}
private void RemoveTabItem()
{
Titles.Remove(Titles.Last());
tabs--;
}
private void AddTabItem()
{
var header = "Tab " + tabs;
var content = "Content " + tabs;
var item = new Item { Header = header, Content = content };
Titles.Add(item);
tabs++;
OnPropertyChanged("Titles");
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged(string propertyName)
{
var handler = PropertyChanged;
handler?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
}
public partial class MainWindow : Window
{
public MainWindowVM x;
public MainWindow()
{
InitializeComponent();
x = new MainWindowVM();
this.DataContext = x;
}
}
After clicking my Play button no new tab is adding
Related
Universal Windows Platform, C#
How can I collapse/expand the child listview of item MainListView listitem from code behind? I have not found anything that works.
I'd like to do this on the SelectionChanged event.
XAML
<ListView x:Name="DestListView" SelectionMode="Single" Margin="0,60,0,0" SelectionChanged="listview_SelectionChanged" >
<ListView.ItemContainerStyle >
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="BorderThickness" Value="0,.5,0,0" />
<Setter Property="BorderBrush" Value="Gainsboro" />
</Style>
</ListView.ItemContainerStyle>
<ListView.ItemTemplate >
<DataTemplate>
<StackPanel>
<Grid>
<Grid HorizontalAlignment="Stretch">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="40"/>
<ColumnDefinition Width="100"/>
<ColumnDefinition Width="50"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="50"/>
</Grid.ColumnDefinitions>
<CheckBox Grid.Column="0" MinWidth="20" />
<TextBlock Grid.Column="1" Text="{Binding destination}" FontSize="20" />
<TextBlock Grid.Column="2" Text="{Binding total_quantity}" FontSize="20" Margin="10,0,0,0"/>
<TextBlock Grid.Column="3" Text="{Binding package_type}" FontSize="20" HorizontalAlignment="Center" Margin="10,0,0,0"/>
<TextBlock Grid.Column="4" Text="{Binding total_weight}" FontSize="20" Margin="10,0,0,0"/>
</Grid>
</Grid>
**<!--Collpase/Expand-->**
<ListView x:Name="DetailListView" ItemsSource="{Binding destination_data}" SelectionMode="Multiple" Margin="20,0,0,0" Visibility="Collapsed" >
<ListView.ItemTemplate >
<DataTemplate >
<StackPanel Orientation="Vertical">
<TextBlock Text="{Binding visual_number}" FontSize="14" Foreground="White" HorizontalAlignment="Stretch" />
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</StackPanel>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
CodeBehind
private void listview_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
//GET THE ITEM
var selectItem = DestListView.Items[DestListView.SelectedIndex];
//GET THE CHILD SOMEHOW
//ListView childListView = (ListView)...not sure what to do here
//if (childListView != null)
//{
// if (childListView.Visibility == Visibility.Collapsed)
// {
// //childListView.Visibility = Visibility.Collapsed;
// }
// else
// {
// //childListView.Visibility = new Visibility;
// }
//}
}
Here is how i would do it.
I would create two DataTemplates one to show when selected (Expanded), another when not expanded.
Below is my ViewModel.
public class MyViewModel
{
public MyViewModel()
{
myItems = new ObservableCollection<MyItems>();
for(int i=1;i<=10;i++)
{
MyItems item = new MyItems();
item.Name = "Main Item " + i.ToString();
ObservableCollection<MySubItems> subItems = new ObservableCollection<MySubItems>();
for (int j=1;j<=5;j++)
{
subItems.Add(new MySubItems() { Title = "Sub Item " + j.ToString() });
}
item.Data = subItems;
myItems.Add(item);
}
}
public ObservableCollection<MyItems> myItems { get; set; }
}
public class MyItems
{
public string Name { get; set; }
public ObservableCollection<MySubItems> Data { get; set; }
}
public class MySubItems
{
public string Title { get; set; }
}
Below is my MainPage.xaml as requested
<Page
x:Class="App2.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:App2"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d">
<Page.DataContext>
<local:MyViewModel/>
</Page.DataContext>
<Page.Resources>
<DataTemplate x:Key="NoSelectDataTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Name}" />
</Grid>
</DataTemplate>
<DataTemplate x:Key="SelectDataTemplate">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Text="{Binding Name}" />
<ListView ItemsSource="{Binding Data}" Grid.Row="1">
<ListView.ItemTemplate>
<DataTemplate>
<TextBlock Text="{Binding Title}" />
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</Grid>
</DataTemplate>
</Page.Resources>
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<ListView HorizontalAlignment="Stretch" VerticalAlignment="Stretch" ItemsSource="{Binding myItems}" SelectionChanged="ListView_SelectionChanged" ItemTemplate="{StaticResource NoSelectDataTemplate}">
<ListView.ItemContainerStyle >
<Style TargetType="ListViewItem">
<Setter Property="HorizontalContentAlignment" Value="Stretch" />
<Setter Property="BorderThickness" Value="0,.5,0,0" />
<Setter Property="BorderBrush" Value="Gainsboro" />
</Style>
</ListView.ItemContainerStyle>
</ListView>
</Grid>
</Page>
And Below is how my SelectionChanged Event Looks like.
private int PreviousIndex;
private void ListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
ListView lv = sender as ListView;
if (PreviousIndex >=0)
{
ListViewItem prevItem = (lv.ContainerFromIndex(PreviousIndex)) as ListViewItem;
prevItem.ContentTemplate = Resources["NoSelectDataTemplate"] as DataTemplate;
}
ListViewItem item = (lv.ContainerFromIndex(lv.SelectedIndex)) as ListViewItem;
item.ContentTemplate = Resources["SelectDataTemplate"] as DataTemplate;
PreviousIndex = lv.SelectedIndex;
}
Here is the Output
What I'm trying to do is bind the controls generated by a ItemsControl.ItemTemplate to a new instance of my ContactInterface class that is created whenever I run my query function.
ContactInterface.cs:
class ContactInterface : INotifyPropertyChanged
{
public string Type { get; set; }
private string firstname;
public string FirstName {
get{return this.firstname;}
set {
if (this.firstname != value) {
this.firstname = value;
this.NotifyPropertyChanged("FirstName");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void NotifyPropertyChanged(string propName)
{
if (this.PropertyChanged != null)
this.PropertyChanged(this, new PropertyChangedEventArgs(propName));
}
}
}
SQL.cs
partial class MainWindow
{
private void selectContact(int? contactID)
{
using (ContactsDataContext context = new ContactsDataContext("Data Source=ds;Initial Catalog=db;Integrated Security=True"))
{
Contact contact = context.Contacts.SingleOrDefault(x => x.ContactID == contactID);
Contact spouse = context.Contacts.SingleOrDefault(x => x.ContactID == contact.Spouse);
Property property = context.Properties.SingleOrDefault(x => x.PropertyID == contact.Address);
ContactInterface selectedContact= new ContactInterface();
selectedContact.FirstName = contact.FirstName;
profileGrid.DataContext = selectedContact;
}
}
MainWindow.xaml
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="300" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<ItemsControl Name="Profile_Page_Controls">
<ItemsControl.ItemsPanel>
<ItemsPanelTemplate>
<Grid Margin="15">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="30" />
<ColumnDefinition Width="100" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="43" />
<RowDefinition Height="43" />
<RowDefinition Height="43" />
<RowDefinition Height="43" />
<RowDefinition Height="43" />
<RowDefinition Height="43" />
<RowDefinition Height="43" />
<RowDefinition Height="43" />
</Grid.RowDefinitions>
</Grid>
</ItemsPanelTemplate>
</ItemsControl.ItemsPanel>
<ItemsControl.ItemTemplate>
<DataTemplate>
<StackPanel>
<TextBlock Text="{Binding TextContent}"/>
<TextBox Height="23" Text="{Binding Path=FirstName, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged }"/>
</StackPanel>
</DataTemplate>
</ItemsControl.ItemTemplate>
<ItemsControl.ItemContainerStyle>
<Style>
<Setter Property="Grid.Column" Value="{Binding profile_Column}" />
<Setter Property ="Grid.Row" Value="{Binding profile_Row}" />
<Setter Property="Grid.ColumnSpan" Value="{Binding profile_Colspan}" />
</Style>
</ItemsControl.ItemContainerStyle>
</ItemsControl>
<CheckBox Name="profile_SpouseCheck" Grid.Column="1" Margin="0,0,0,0" Checked="profile_SpouseCheck_Checked_1" Unchecked="profile_SpouseCheck_Checked_1"> Spouse</CheckBox>
</Grid>
My plan is to make a new ContactInterface instance every time a user runs the selectContact() function. That new instance will be bound to the generated controls, so when the user makes and saves a change, the textboxes will update that ContactInterface instance and my other functions can grab the data from that ContactInterface to make changes to the database.
Any ideas?
I am trying to make a custom user control that I can reuse across all of my views. My BaseViewModel has a property called ViewAlerts that is intended to be used to show alerts consistently across the application (such as successful updates, failed requests, etc.). I was able to get to the point where my custom control is buildable and has a property for binding, but the collection of alerts is never show. I am statically defining some alerts in my base view model for testing purposes, and am not able to get the alerts to show (seems like a problem with an INotifyPropertyChanged but my bindable property inherits from ObservableCollection<> so it should be automatically handling that I think).
Here is my custom control so far:
<UserControl.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../../Resources/MMJCeoResources.xaml" />
<ResourceDictionary>
<Style TargetType="TextBlock" x:Key="AlertTextStyle">
<Setter Property="FontSize" Value="15"></Setter>
<Setter Property="Margin" Value="10" />
<Setter Property="Padding" Value="10" />
</Style>
<DataTemplate x:Key="DangerAlert">
<Grid Background="LightPink">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="10*"/>
</Grid.RowDefinitions>
<Border Width="10"
Height="10"
BorderBrush="DarkRed"
HorizontalAlignment="Right"
Margin="5"
Grid.Row="0">
<TextBlock Text="X" />
</Border>
<TextBlock Grid.Row="1" Text="{Binding Message}" Style="{StaticResource AlertTextStyle}" Foreground="DarkRed"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="SuccessAlert">
<Grid Background="LightGreen">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="10*"/>
</Grid.RowDefinitions>
<Border Width="10"
Height="10"
BorderBrush="DarkGreen"
HorizontalAlignment="Right"
Margin="5"
Grid.Row="0">
<TextBlock Text="X" />
</Border>
<TextBlock Grid.Row="1" Text="{Binding Message}" Style="{StaticResource AlertTextStyle}" Foreground="DarkGreen"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="InfoAlert">
<Grid Background="LightGreen">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="10*"/>
</Grid.RowDefinitions>
<Border Width="10"
Height="10"
BorderBrush="DarkGreen"
HorizontalAlignment="Right"
Margin="5"
Grid.Row="0">
<TextBlock Text="X" />
</Border>
<TextBlock Grid.Row="1" Text="{Binding Message}" Style="{StaticResource AlertTextStyle}" Foreground="DarkGreen"/>
</Grid>
</DataTemplate>
<DataTemplate x:Key="WarningAlert">
<Grid Background="LightSalmon">
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="10*"/>
</Grid.RowDefinitions>
<Border Width="10"
Height="10"
BorderBrush="DarkOrange"
HorizontalAlignment="Right"
Margin="5"
Grid.Row="0">
<TextBlock Text="X" />
</Border>
<TextBlock Grid.Row="1" Text="{Binding Message}" Style="{StaticResource AlertTextStyle}" Foreground="DarkOrange"/>
</Grid>
</DataTemplate>
</ResourceDictionary>
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
</UserControl.Resources>
<Grid>
<ItemsControl ItemsSource="{Binding Path=Alerts}"
ItemTemplateSelector="{StaticResource AlertDataTemplateSelector}">
</ItemsControl>
</Grid>
</UserControl>
The Code Behind for the control:
public sealed partial class AlertControl : UserControl
{
public static readonly DependencyProperty AlertsProperty = DependencyProperty.Register(
"Alerts", typeof (ObservableList<Alert>), typeof (AlertControl), new PropertyMetadata(default(ObservableList<Alert>), OnAlertsChanged));
public ObservableList<Alert> Alerts
{
get { return (ObservableList<Alert>) GetValue(AlertsProperty); }
set { SetValue(AlertsProperty, value); }
}
//I was trying to adapt another tutorial to what I was trying to accomplish but only got this far
public static void OnAlertsChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var old = e.OldValue as ObservableList<Alert>;
var me = sender as AlertControl;
if (old != null)
{
old.CollectionChanged -= me.OnAlertCollectionChanged;
}
var n = e.NewValue as ObservableList<Alert>;
if (n != null)
n.CollectionChanged += me.OnAlertCollectionChanged;
}
private void OnAlertCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.Action == NotifyCollectionChangedAction.Reset)
{
Alerts.Clear();
var n = e.NewItems as ObservableList<Alert>;
Alerts.AddRange(n);
}
}
public AlertControl()
{
this.InitializeComponent();
DataContext = this;
}
}
an example implementation:
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<StackPanel Orientation="Vertical" HorizontalAlignment="Stretch">
<TextBlock Style="{StaticResource PageTitle}" Text="User Information" />
<controls:AlertControl Alerts="{Binding ViewAlerts}" />
in this implementation, the ViewAlerts property has 4 statically defined alerts in it, so I know there are values that should be showing up.
You should give your inner Grid the DataContext to this and not to the Control itself, because then the outer binding will search for your ViewAlerts inside the Control
<Grid x:Name="InnerGrid">
<ItemsControl ItemsSource="{Binding Path=Alerts}"
ItemTemplateSelector="{StaticResource AlertDataTemplateSelector}">
</ItemsControl>
</Grid>
public AlertControl()
{
this.InitializeComponent();
InnerGrid.DataContext = this;
}
After that you can Bind to Alerts, and Alerts will be binded to the ItemsControl inside your InnerGrid
I am using Caliburn.Micro to do convention based binding of the contents of my listbox from a BindableCollection in my ViewModel.
I want to perform Validation on it so that when there is no selection and the user exits the form they get that nice red line around the listbox with the error message that they have to select a value. So far Caliburn has worked great for textbox validation but I can't seem to get it to work on the listbox!
On a side note, is there any way to forcibly run a complete validation from the VM? Currently I am merely doing manual validation by checking the values and changing them so it triggers the Validator which is a bit backwards..
Here is the code for my view:
<UserControl x:Class="AddSessionDialogView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:toolkit="http://schemas.microsoft.com/winfx/2006/xaml/presentation/toolkit">
<toolkit:BusyIndicator IsBusy="{Binding IsBusy}" BusyContent="{Binding IsBusyStatusDisplay}">
<Grid x:Name="LayoutRoot" Background="White">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="100" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="auto"/>
<RowDefinition Height="*"/>
<RowDefinition Height="auto" />
<RowDefinition Height="auto"/>
</Grid.RowDefinitions>
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="Margin" Value="5,9" />
</Style>
<Style TargetType="TextBox">
<Setter Property="Margin" Value="5" />
</Style>
</Grid.Resources>
<TextBlock Text="Session Name" />
<TextBox x:Name="SessionName" Grid.Column="1" />
<TextBlock Text="Scenario" Grid.Row="1" />
<ListBox x:Name="Scenarios" Grid.Row="1" Grid.Column="1" DisplayMemberPath="Name" Margin="5" />
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Bottom" Grid.Column="1" Grid.Row="3" Margin="5">
<Button x:Name="Cancel" Height="28" Margin="5" Content="Cancel" Padding="0,2" Width="75" />
<Button x:Name="OK" Height="28" Margin="5" Content="OK" Padding="0,2" Width="100" />
</StackPanel>
</Grid>
</toolkit:BusyIndicator>
Here is the (relevant) code for my viewmodel:
public BindableCollection<Scenario> Scenarios { get; set; }
[Required(ErrorMessage = "You must select a scenario")]
public Scenario SelectedScenario { get; set; }
private string _sessionName;
[Required(ErrorMessage="Session Name is invalid")]
public string SessionName
{
get { return _sessionName; }
set { _sessionName = value; NotifyOfPropertyChange(() => SessionName); }
}
public IEnumerable<IResult> OK()
{
if (SelectedScenario == null)
{
// This forces validation check, but doesnt show validation error on the view!
SelectedScenario = new Scenario();
SelectedScenario = null;
}
if (SessionName == null)
SessionName = "";
if (Validator.TryValidateObject(this, new ValidationContext(this), new List<ValidationResult>()))
{
IsBusy = true;
IsBusyStatusDisplay = "Creating Session...";
yield return new CreateSessionResult(SelectedScenario.Id, SessionName);
IsBusy = false;
yield return Close();
}
}
I was working on creating a reusable custom control (not a user control) in WPF. I created the XAML in the Themes/Generic.xaml file and I setup the "lookless" functionality in the control's CS file:
AddressField.cs
using ...;
namespace MyNamespace
{
[TemplatePart(Name = AddressField.ElementAddress1TextBox, Type = typeof(TextBox))]
public class AddressField : Control
{
private const String ElementAddress1TextBox = "PART_Address1TextBox";
public AddressEntity Address
{
get { return (AddressEntity)GetValue(AddressProperty); }
set { SetValue(AddressProperty, value); }
}
public static readonly DependencyProperty AddressProperty =
DependencyProperty.Register("Address", typeof(AddressEntity), typeof(AddressField), new UIPropertyMetadata(null, new PropertyChangedCallback(OnAddressPropertyChangedCallback)));
static AddressField()
{
DefaultStyleKeyProperty.OverrideMetadata(typeof(AddressField), new FrameworkPropertyMetadata(typeof(AddressField)));
}
}
}
Themes\Generic.xaml
<ResourceDictionary
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:MyNamespace"
>
<Style TargetType="{x:Type local:AddressField}">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type local:AddressField}">
<StackPanel>
<Grid x:Name="StandardView">
<Grid.Resources>
<Style TargetType="TextBlock">
<Setter Property="Height" Value="17" />
<Setter Property="Margin" Value="3,3,3,3" />
</Style>
<Style TargetType="TextBox">
<Setter Property="Height" Value="23" />
<Setter Property="Margin" Value="3,3,3,3" />
</Style>
</Grid.Resources>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<!-- Address 1, Address2-->
<TextBlock Grid.Row="0" Grid.Column="0" VerticalAlignment="Center" HorizontalAlignment="Right" Text="Address:" TextWrapping="NoWrap" />
<TextBox Grid.Row="0" Grid.Column="1" Grid.ColumnSpan="8" VerticalAlignment="Stretch" HorizontalAlignment="Stretch" MinWidth="300"
x:Name="PART_Address1TextBox" Text="{Binding Path=Address1}" />
</Grid>
</StackPanel>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</ResourceDictionary>
Form.xaml
<Window x:Class="NIC.BackOffice.Casino.RegistrationEntryForm"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:nic="clr-namespace:MyNamespace;assembly=MyStuff">
<Canvas>
<nic:AddressField Canvas.Left="10" Canvas.Top="10"
x:Name="OfficeAddressField" Address={Binding Path=OAddress} />
</Canvas>
</Window>
Form.cs
using ...;
namespace MyNamespace
{
public partial class Form : Window
{
public Form()
{
InitializeComponent();
OAddress = new AddressEntity("1234 Testing Lane");
}
public AddressEntity OAddress { get; set; }
}
}
UPDATED: The prior code is an update from my previous code (removed a lotta fluff just to get down to the ONE example). Though, for some reason Address (within OfficeAddressField) is never ever updated even though I set the binding of OAddress to the AddressField object.
You don't need to refresh the DataContext. In fact, your control shouldn't be using it. Make Address a DependencyProperty and then use a TemplateBinding in your control's template:
<TextBox Text="{TemplateBinding Address.Address1}"/>
You should consider raising an event when the address dp changes.