Related
I am new to WPF and also the MVVM pattern, I tried to create a simple WPF project to query a database of I-Shape Steel Profiles and show it to the user through the DataGrid. After I have successfully done it, I am now moving to the next part: Letting the user to add new steel profiles to the DataGrid by filling out a set of TextBoxes.
Model
namespace SectionGuardWPF.MVVM.Model
{
public class IProfileModel : ObservableObject
{
#region Private Fields
public short _recno;
public string _name;
public string _staadName;
public double _ax;
public double _d;
public double _bf;
public double _tf;
public double _tw;
public double _iz;
public double _ix;
public double _ct;
public double _iy;
public double _zx;
public double _zy;
#endregion
#region Public Properties
/// <summary>
/// Properties are given NotifyPropertyChanged method to allow for a change in property to be notified
/// </summary>
public short RECNO
{
get { return _recno; }
set
{
_recno = value;
OnPropertyChanged();
}
}
public string Name
{
get { return _name; }
set
{
_name = value;
OnPropertyChanged();
}
}
...
// Repeated for the other fields
ObservableObject: Base class that implements INotifyPropertyChanged
namespace SectionGuardWPF.Core
{
public class ObservableObject : INotifyPropertyChanged
{
/// <summary>
/// Raised when a property on this object has a new value.
/// </summary>
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Raises this object's PropertyChanged event.
/// </summary>
protected void OnPropertyChanged([CallerMemberName] string name = null) // If you use the CallerMemberName attribute, calls to the NotifyPropertyChanged method don't have to specify the property name as a string argument
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
}
}
}
RelayCommand
namespace SectionGuardWPF.Core
{
class RelayCommand : ICommand
{
private Action<object> _execute;
private Func<object, bool> _canExecute;
public event EventHandler CanExecuteChanged
{
add { CommandManager.RequerySuggested += value; }
remove { CommandManager.RequerySuggested -= value; }
}
public RelayCommand(Action<object> execute, Func<object,bool> canExecute=null)
{
_execute = execute;
_canExecute = canExecute;
}
public bool CanExecute(object parameter)
{
return _canExecute == null || _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
}
}
View Model
namespace SectionGuardWPF.MVVM.ViewModel
{
public class IProfilesViewModel:ObservableObject
{
#region Private Fields
private readonly string _connectionString = //Hidden
private ObservableCollection<IProfileModel> _iProfiles;
private ICommand _getIProfilesCommand;
private ICommand _addNewIProfileCommand;
private IProfileModel _iProfile = new IProfileModel();
#endregion
#region Constructor
public IProfilesViewModel()
{
// Set default Profile Database for the DataGrid upon View instantiation
IProfiles = GetIProfiles();
}
#endregion
#region Public Properties and Commands
/// <summary>
/// Public properties of the IProfilesViewModel Class (used for view binding with IProfilesSubView)
/// </summary>
public ObservableCollection<IProfileModel> IProfiles
{
get { return _iProfiles; }
set
{
_iProfiles = value;
OnPropertyChanged();
}
}
public IProfileModel IProfile
{
get { return _iProfile; }
set
{
_iProfile = value;
OnPropertyChanged();
}
}
public ICommand GetIProfilesCommand
{
get
{
if (_getIProfilesCommand == null)
{
_getIProfilesCommand = new RelayCommand(
param => GetIProfiles()
);
}
return _getIProfilesCommand;
}
}
public ICommand AddNewIProfileCommand
{
get
{
if (_addNewIProfileCommand == null)
{
_addNewIProfileCommand = new RelayCommand(
param => AddNewIProfile()
);
}
return _addNewIProfileCommand;
}
}
#endregion
#region Private Methods
private ObservableCollection<IProfileModel> GetIProfiles()
{
TableDataProvider tableDataProvider = new TableDataProvider(_connectionString);
tableDataProvider.QueryString = "SELECT * FROM [I Shape]";
IEnumerable<IProfileModel> iProfiles = tableDataProvider.Query<IProfileModel>();
ObservableCollection<IProfileModel> iProfileObsvCol = new ObservableCollection<IProfileModel>(iProfiles);
return iProfileObsvCol;
}
private void AddNewIProfile()
{
IProfiles.Add(
new IProfileModel
{
RECNO = IProfile.RECNO,
Name = IProfile.Name,
StaadName = IProfile.StaadName,
AX = IProfile.AX,
D = IProfile.D,
Bf = IProfile.Bf,
Tf = IProfile.Tf,
Tw = IProfile.Tw,
Ix = IProfile.Ix,
Iy = IProfile.Iy,
Iz = IProfile.Iz,
Ct = IProfile.Ct,
Zx = IProfile.Zx,
Zy = IProfile.Zy
}
);
}
#endregion
}
}
View
<UserControl x:Class="SectionGuardWPF.MVVM.View.IProfilesSubView"
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:SectionGuardWPF.MVVM.View"
xmlns:viewModel= "clr-namespace:SectionGuardWPF.MVVM.ViewModel"
xmlns:view="clr-namespace:SectionGuardWPF.MVVM.View"
mc:Ignorable="d"
d:DesignHeight="580" d:DesignWidth="1300">
<UserControl.DataContext>
<viewModel:IProfilesViewModel/>
</UserControl.DataContext>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="620"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<DataGrid x:Name="ProfilesDataGrid"
x:FieldModifier="public"
ItemsSource="{Binding IProfiles, Mode=TwoWay}">
</DataGrid>
<Border Grid.Column="1"
CornerRadius="20"
Background ="White"
Margin="10">
<Grid Margin="10">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition/>
<RowDefinition Height="150"/>
</Grid.RowDefinitions>
<TextBlock Text="I-Profiles Data Viewer"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="20,0,0,0"
Foreground="Black"
FontSize="22"/>
<Grid Grid.Row="1">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<TextBlock Text="RECNO"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="20,0,0,0"
Foreground="#1A80FA"
Grid.Column="0"
Grid.Row="0"
FontSize="14"/>
<TextBox x:Name="RECNOTextBox"
Margin="0,0,20,0"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Style="{StaticResource ParameterTextbox}"
Grid.Column="0"
Grid.Row="0"
Text="{Binding IProfile.RECNO, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<TextBlock Text="Name"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="20,0,0,0"
Foreground="#1A80FA"
Grid.Column="0"
Grid.Row="1"
FontSize="14"/>
<TextBox x:Name="NameTextBox"
Margin="0,0,20,0"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Style="{StaticResource ParameterTextbox}"
Grid.Column="0"
Grid.Row="1"
Text="{Binding IProfile.Name, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<TextBlock Text="StaadName"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="20,0,0,0"
Foreground="#1A80FA"
Grid.Column="0"
Grid.Row="2"
FontSize="14"/>
<TextBox x:Name="StaadNameTextBox"
Margin="0,0,20,0"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Style="{StaticResource ParameterTextbox}"
Grid.Column="0"
Grid.Row="2"
Text="{Binding IProfile.StaadName, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<TextBlock Text="AX"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="20,0,0,0"
Foreground="#1A80FA"
Grid.Column="0"
Grid.Row="3"
FontSize="18"/>
<TextBox x:Name="AXTextBox"
Margin="0,0,20,0"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Style="{StaticResource ParameterTextbox}"
Grid.Column="0"
Grid.Row="3"
Text="{Binding IProfile.AX, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<TextBlock Text="D"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="20,0,0,0"
Foreground="#1A80FA"
Grid.Column="0"
Grid.Row="4"
FontSize="18"/>
<TextBox x:Name="DTextBox"
Margin="0,0,20,0"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Style="{StaticResource ParameterTextbox}"
Grid.Column="0"
Grid.Row="4"
Text="{Binding IProfile.D, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<TextBlock Text="Bf"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="20,0,0,0"
Foreground="#1A80FA"
Grid.Column="0"
Grid.Row="5"
FontSize="18"/>
<TextBox x:Name="BfTextBox"
Margin="0,0,20,0"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Style="{StaticResource ParameterTextbox}"
Grid.Column="0"
Grid.Row="5"
Text="{Binding IProfile.Bf, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<TextBlock Text="Tf"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="20,0,0,0"
Foreground="#1A80FA"
Grid.Column="0"
Grid.Row="6"
FontSize="18"/>
<TextBox x:Name="TfTextBox"
Margin="0,0,20,0"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Style="{StaticResource ParameterTextbox}"
Grid.Column="0"
Grid.Row="6"
Text="{Binding IProfile.Tf, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<TextBlock Text="Tw"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="20,0,0,0"
Foreground="#1A80FA"
Grid.Column="1"
Grid.Row="0"
FontSize="18"/>
<TextBox x:Name="TwTextBox"
Margin="0,0,20,0"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Style="{StaticResource ParameterTextbox}"
Grid.Column="1"
Grid.Row="0"
Text="{Binding IProfile.Tw, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<TextBlock Text="Ix"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="20,0,0,0"
Foreground="#1A80FA"
Grid.Column="1"
Grid.Row="1"
FontSize="18"/>
<TextBox x:Name="IxTextBox"
Margin="0,0,20,0"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Style="{StaticResource ParameterTextbox}"
Grid.Column="1"
Grid.Row="1"
Text="{Binding IProfile.Ix, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<TextBlock Text="Iy"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="20,0,0,0"
Foreground="#1A80FA"
Grid.Column="1"
Grid.Row="2"
FontSize="18"/>
<TextBox x:Name="IyTextBox"
Margin="0,0,20,0"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Style="{StaticResource ParameterTextbox}"
Grid.Column="1"
Grid.Row="2"
Text="{Binding IProfile.Iy, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<TextBlock Text="Iz"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="20,0,0,0"
Foreground="#1A80FA"
Grid.Column="1"
Grid.Row="3"
FontSize="18"/>
<TextBox x:Name="IzTextBox"
Margin="0,0,20,0"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Style="{StaticResource ParameterTextbox}"
Grid.Column="1"
Grid.Row="3"
Text="{Binding IProfile.Iz, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<TextBlock Text="Ct"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="20,0,0,0"
Foreground="#1A80FA"
Grid.Column="1"
Grid.Row="4"
FontSize="18"/>
<TextBox x:Name="CtTextBox"
Margin="0,0,20,0"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Style="{StaticResource ParameterTextbox}"
Grid.Column="1"
Grid.Row="4"
Text="{Binding IProfile.Ct, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<TextBlock Text="Zx"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="20,0,0,0"
Foreground="#1A80FA"
Grid.Column="1"
Grid.Row="5"
FontSize="18"/>
<TextBox x:Name="ZxTextBox"
Margin="0,0,20,0"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Style="{StaticResource ParameterTextbox}"
Grid.Column="1"
Grid.Row="5"
Text="{Binding IProfile.Zx, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
<TextBlock Text="Zy"
VerticalAlignment="Center"
HorizontalAlignment="Left"
Margin="20,0,0,0"
Foreground="#1A80FA"
Grid.Column="1"
Grid.Row="6"
FontSize="18"/>
<TextBox x:Name="ZyTextBox"
Margin="0,0,20,0"
VerticalAlignment="Center"
HorizontalAlignment="Right"
Style="{StaticResource ParameterTextbox}"
Grid.Column="1"
Grid.Row="6"
Text="{Binding IProfile.Zy, UpdateSourceTrigger=PropertyChanged, Mode=TwoWay}"/>
</Grid>
<StackPanel Grid.Row="2"
Orientation="Horizontal">
<Button x:Name="AddButton"
Style="{StaticResource AddButton}"
Content="Add"
Background="#28C941"
Height="50"
Width="150"
Margin="85,0,0,0"
Command="{Binding AddNewIProfileCommand}"/>
<Button x:Name="EditButton"
Style="{StaticResource AddButton}"
Content="Edit"
Background="#FFBD2E"
Height="50"
Width="150"
Margin="20,0,0,0"/>
<Button x:Name="DeleteButton"
Style="{StaticResource AddButton}"
Content="Delete"
Background="#FF6059"
Height="50"
Width="150"
Margin="20,0,0,0"/>
</StackPanel>
</Grid>
</Border>
</Grid>
</UserControl>
My Model class is a class called the IProfileModel that represents the I-Shape Profiles, I have made so that it inherits from the ObservableObject class so that it can use the NotifyPropertyChanged methods and I have made so that the properties of the Model class has implemented the OnPropertyChanged() Method.
In my View, I have bound the source of the DataGrid to the IProfiles which is an ObservableCollection that stores instances of the IProfileModel. Each TextBox corresponds to one property of the IProfileModel class, thus the Text property of each TextBox is bound to its respective nested property of the IProfile property of the ViewModel. The "Add" Button is bound to the respective ICommand in the ViewModel called the AddNewIProfileCommand
In my ViewModel, I have added the IProfileModel as one of its properties using the name IProfile, the TextBox.Text properties are bound to the nested properties of the IProfile as shown in the XAML of the View. As for the AddNewIProfileCommand, I have made so that it corresponds to a private method called the AddNewIProfile() which will add a new IProfileModel object whose properties will refer to the nested properties of the IProfile property that is bound to the TextBoxes.
Edit:
I want to add that the AddNewIProfile() will add the new IProfileModel object to the IProfiles which is bound to the DataGrid
My main issue is that whenever I modified the TextBoxes and then clicked on the Button to add the profiles to the DataGrid, the newly added entry to the DataGrid is always a IProfileModel with empty property values (all string properties of the IProfileModel are null and all numerical type properties are 0). It seems like modifying the TextBoxes does not change the nested properties of the IProfile even though I have set the UpdateSourceTrigger to PropertyChanged and the Mode to Two Way and the IProfile itself is of the IProfileModel class which has inherited from the ObservableObject class.
Lastly, I know that my question is quite similar to this one but I have followed the suggestions there and tried to match their solution but I somehow can't get it to work.
Thanks!
Edit:
Added some before - after picture of the DataGrid after the "Add" Button is pressed:
Edit:
The ParameterTextbox Style which was the cause of the error as pointed out by Cédric Moers in the comments:
<Style TargetType="{x:Type TextBox}"
x:Key="ParameterTextbox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type TextBox}">
<Border CornerRadius="5"
Background="White"
Width="180"
Height="35"
BorderThickness="3"
BorderBrush="#EAEAEA">
<Grid>
<Rectangle StrokeThickness="1"/>
<TextBox Margin="1"
Text="{TemplateBinding Text}"
BorderThickness="0"
Background="Transparent"
VerticalContentAlignment="Center"
Padding="5"
Foreground="Black"
x:Name="SearchBox"/>
</Grid>
</Border>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
I tried to replicate your problem but I had to remove the styles since you did not provide them. It works at my side, so perhaps the problem lies within the style?
Please delete your styles for the textboxes (ParameterTextbox) and see if it works then. If you can provide me with the source code for the style, I can take a look at it. Maybe you are overriding the text property.
edit after it turned out the style was the issue
here is an example of the style you want to accomplish in a minimalistic way.
<UserControl.Resources>
<ControlTemplate x:Key="RoundedTextBoxCt">
<Border
Width="{TemplateBinding Width}"
Height="{TemplateBinding Height}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Background="{TemplateBinding Background}"
x:Name="Bd"
CornerRadius="5">
<ScrollViewer
Padding="{TemplateBinding Padding}"
VerticalContentAlignment="{TemplateBinding VerticalContentAlignment}"
Foreground="{TemplateBinding Foreground}"
x:Name="PART_ContentHost"/>
</Border>
</ControlTemplate>
<Style x:Key="ParameterTextBox" TargetType="TextBox">
<Setter Property="Width" Value="180"/>
<Setter Property="Height" Value="35"/>
<Setter Property="VerticalContentAlignment" Value="Center"/>
<Setter Property="Padding" Value="5"/>
<Setter Property="Foreground" Value="Black"/>
<Setter Property="BorderBrush" Value="#EAEAEA"/>
<Setter Property="BorderThickness" Value="3"/>
<Setter Property="Background" Value="White"/>
<Setter Property="Template" Value="{StaticResource RoundedTextBoxCt}"/>
</Style>
...
</UserControl.Resources>
I made the control template as a separate resource, this way 'rounded textbox' can be put inside of some 'shared' assembly, and you will be able to use it for other projects as well.
It is minimalistic, as in the minimal you'll need. If you want a full-fledged text box, copy the style from here and modify it: https://learn.microsoft.com/en-us/dotnet/desktop/wpf/controls/textbox-styles-and-templates?view=netframeworkdesktop-4.8
it might look scary, but most of the time it comes down to modifying only a few rules. Once you get the hang of it, it's quite easy.
Instead of working with the setters, and even a separate control template resource, you could hard-code everything within the control template, WITHIN the setter of the control template of the textbox style, but that's up to you.
Good luck!
I need to change the color of a rectangle in a GridView when the item is selected.
Unselected item
Selected item
My Main Page in XAML.
<Page
x:Class="GridViewWithSelectedItem.Views.MainPage"
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:views="using:GridViewWithSelectedItem.Views"
Style="{StaticResource PageStyle}"
mc:Ignorable="d">
<Page.Resources>
<DataTemplate x:Key="TileTemplate" x:DataType="views:Article">
<Border BorderThickness="2,2,2,2" BorderBrush="#FF868484" Margin="3,3,3,3" HorizontalAlignment="Stretch" MaxWidth="600" MinWidth="525">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="10"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition Height="60"/>
<RowDefinition/>
</Grid.RowDefinitions>
<Rectangle Fill="Black" Grid.RowSpan="3"/>
<StackPanel Orientation="Horizontal" Grid.Row="0" Grid.Column="1">
<TextBlock FontSize="20" Margin="0,0,5,0" TextWrapping="Wrap" Foreground="DarkBlue" FontWeight="Bold" Text="{x:Bind Number}"/>
<TextBlock FontSize="20" TextWrapping="Wrap" Foreground="DarkBlue" Text="{x:Bind Title}" FontWeight="Bold"/>
</StackPanel>
<TextBlock Grid.Row="1" Grid.Column="1" FontSize="20" Text="{x:Bind Description}" TextWrapping="WrapWholeWords"/>
<StackPanel Background="LightBlue" Padding="5,0,0,0" Grid.Row="2" Grid.Column="1">
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="20" Margin="0,0,5,0" TextWrapping="Wrap">Date :</TextBlock>
<TextBlock Foreground="Red" FontSize="20" TextWrapping="Wrap" Text="{x:Bind Date}" FontWeight="Bold"/>
</StackPanel>
</StackPanel>
</Grid>
</Border>
</DataTemplate>
</Page.Resources>
<Grid x:Name="ContentArea" Margin="{StaticResource MediumLeftRightMargin}">
<Grid Background="White" VerticalAlignment="Top" HorizontalAlignment="Stretch" Margin="0,25,0,0">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="600"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="60"/>
<RowDefinition Height="800"/>
</Grid.RowDefinitions>
<TextBlock Text="The Guardian" FontSize="35" FontWeight="Bold" Grid.ColumnSpan="2" HorizontalAlignment="Center"/>
<GridView
BorderThickness="2,2,0,2" BorderBrush="#FF868484"
MinWidth="600"
Grid.Column="0"
Grid.Row="1"
Padding="5,5,5,5"
HorizontalAlignment="Center"
CanDragItems="False"
IsItemClickEnabled="true"
IsTapEnabled="False"
IsSwipeEnabled="False"
ItemsSource="{x:Bind Articles}"
ItemTemplate="{StaticResource TileTemplate}"
SelectedItem="{x:Bind Mode=TwoWay, Path=SelectedArticle}"
/>
<RelativePanel Grid.Row="1" Grid.Column="1" Background="WhiteSmoke" BorderThickness="2" BorderBrush="#FF868484" Padding="10">
<Grid RelativePanel.AlignLeftWithPanel="True" RelativePanel.AlignRightWithPanel="True">
<Grid VerticalAlignment="Top">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<StackPanel Orientation="Horizontal" Grid.Row="0">
<TextBlock FontSize="20" Margin="0,0,5,0" TextWrapping="Wrap" Foreground="DarkBlue" FontWeight="Bold" Text="{x:Bind Path=SelectedArticle.Number, Mode=OneWay}"/>
<TextBlock FontSize="20" TextWrapping="Wrap" Foreground="DarkBlue" Text="{x:Bind Path=SelectedArticle.Title, Mode=OneWay}" FontWeight="Bold"/>
</StackPanel>
<TextBlock Grid.Row="1" FontSize="20" Text="{x:Bind Path=SelectedArticle.Description, Mode=OneWay}" TextWrapping="WrapWholeWords"/>
</Grid>
</Grid>
<RelativePanel Background="LightBlue" Padding="5,0,0,0" RelativePanel.AlignBottomWithPanel="True" RelativePanel.AlignLeftWithPanel="True" RelativePanel.AlignRightWithPanel="True">
<StackPanel Orientation="Horizontal">
<TextBlock FontSize="20" Margin="0,0,5,0" TextWrapping="Wrap">Date :</TextBlock>
<TextBlock Foreground="Red" FontSize="20" TextWrapping="Wrap" Text="{x:Bind Path=SelectedArticle.Date, Mode=OneWay}" FontWeight="Bold"/>
</StackPanel>
</RelativePanel>
</RelativePanel>
</Grid>
</Grid>
</Page>
And the class of my XAML Page.
using System;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Runtime.CompilerServices;
using Windows.UI.Xaml.Controls;
namespace GridViewWithSelectedItem.Views
{
public sealed partial class MainPage : Page, INotifyPropertyChanged
{
public ObservableCollection<Article> Articles;
private Article _selectedArticle;
public Article SelectedArticle
{
get { return _selectedArticle; }
set { Set(ref _selectedArticle, value); }
}
public MainPage()
{
InitializeComponent();
Articles = new ObservableCollection<Article>();
Articles.Add(new Article(0, "Uighurs", "Being young' leads to detention in China's Xinjiang region", DateTime.Parse("09/12/2020")));
Articles.Add(new Article(1, "Brexit", "Chances of Brexit deal hang on Boris Johnson and Ursula von der Leyen dinner", DateTime.Parse("09/12/2020")));
Articles.Add(new Article(2, "Environment", "Secretive ‘gold rush’ for deep-sea mining dominated by handful of firms", DateTime.Parse("09/12/2020")));
Articles.Add(new Article(3, "Juukan Gerge induiry", "Juukan Gorge inquiry: Rio Tinto's decision to blow up Indigenous rock shelters 'inexcusable'", DateTime.Parse("09/12/2020")));
Articles.Add(new Article(4, "Australia", "British journalist uncovered Australian woman's alleged plan to kill parents on dark web, police say", DateTime.Parse("09/12/2020")));
Articles.Add(new Article(5, "Coronavirus", "Nine out of 10 in poor nations to miss out on inoculation as west buys up Covid vaccines", DateTime.Parse("09/12/2020")));
}
public event PropertyChangedEventHandler PropertyChanged;
private void Set<T>(ref T storage, T value, [CallerMemberName]string propertyName = null)
{
if (Equals(storage, value))
{
return;
}
storage = value;
OnPropertyChanged(propertyName);
}
private void OnPropertyChanged(string propertyName) => PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
public class Article
{
public int Number { get; set; }
public string Title { get; set; }
public string Description { get; set; }
public DateTime Date { get; set; }
public Article(int number, string title, string description, DateTime date)
{
Number = number;
Title = title;
Description = description;
Date = Date;
}
}
}
I see AutomationProperty.name can help me but i don't understand how to use it.
I found a way to change the color of a selected item in my class but i need to recreate the collection and i cost lot of resources. I think its possible to make it in XAML code.
Edit: I made a simple exemple of my code.
OneDrive link
You could add a Brush property into the Article class, and bind the Brush property to Rectangle.Fill property of your DataTemplate to change the color when an item of GridView control is selected.
Please check the following code:
In DataTemplate of your xaml file:
<Rectangle x:Name="rectangle" Fill="{x:Bind Brush}" Grid.RowSpan="3"/>
……
<GridView …… SelectionChanged="GridView_SelectionChanged" />
In code-behind:
public class Article
{
……
public SolidColorBrush Brush { get; set; }
public Article(int number, string title, string description, DateTime date)
{
……
Brush = new SolidColorBrush(Colors.Black);
}
}
Add a _preSelectedArticle property to save the previous item in MainPage class:
private Article _preSelectedArticle;
Change the value of Brush property of selected item and previous selected item:
private void GridView_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
if(_preSelectedArticle==null)
{
SelectedArticle.Brush.Color = Colors.Green;
_preSelectedArticle = SelectedArticle;
}
if (_preSelectedArticle!=null&&_preSelectedArticle!= SelectedArticle)
{
_preSelectedArticle.Brush.Color = Colors.Black;
SelectedArticle.Brush.Color = Colors.Green;
_preSelectedArticle = SelectedArticle;
}
}
What I want to do is to be able to access an object's properties through a bound textblock that is found in a viewModel class. So say I want to access the OrderID of the Orders class in a bound textblock that is stored in a viewModel class.
What I have for that is:
<textblock text="{Binding Path=Order.OrderID}"/>
This is connected to the order's orderID as when I change the OrderID in the ViewModel class the change is reflected in the textblock. The problem occurs when I try to load the OrderID from another class.
The Other class:
public class ModifyOrder
{
private ViewModel boundData;
public ModifyOrder()
{
boundData = new ViewModel();
}
public void ChangeOrderID()
{
boundData.Order.OrderID = 10;
}
}
The changes here don't get transfered to the static _Order in the ViewModel class.
This is the viewModel class:
public class ViewModel : INotifyPropertyChanged
{
private Orders _Order;
public Orders Order
{
get { return _Order; }
set
{
if (_Order != value)
{
_Order = value;
}
}
}
public ViewModel()
{
Order = new Orders();
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
I have the ViewModel class loaded into the UI's DataContext and my other bound variables in the ViewModel class work fine but for some reason either the bound textblock isn't accessing the Order.OrderID (Which I don't think is the problem since I can modify the Order.OrderID in the ViewModel class and the changes are reflected) OR the class that's modifying my Order isn't able to modify the OrderID.
I've already tried to load a new Order class with the new OrderID and then try to load the ViewModel's _Order with the ModifyOrder's new Order but that hasn't worked out either.
This is the Orders class:
public class Orders : INotifyPropertyChanged
{
private int _OrderID;
public int OrderID
{
get { return _OrderID; }
set
{
if(_OrderID != value)
{
_OrderID = Value
OnPropertyChanged(nameof(OrderID));
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
private void OnPropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
<Page x:Class="SPWally.FunctionalPages.LookupOrders"
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:SPWally.FunctionalPages"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
Title="LookupOrders">
<Grid Background="AliceBlue">
<Grid.RowDefinitions>
<RowDefinition Height="50"/>
<RowDefinition Height="30"/>
<RowDefinition Height="*"/>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="20"/>
<RowDefinition Height="*"/>
<RowDefinition Height="50"/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="*"/>
</Grid.ColumnDefinitions>
<TextBlock Grid.Row="0" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center" FontSize="30" Text="Search For Order" />
<TextBlock Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,335,0" Text="OrderID: " />
<TextBox Grid.Row="1" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Width="300" Margin="0,0,20,0" Text="{Binding Path=OrderIDSearch, Mode=OneWayToSource, UpdateSourceTrigger=PropertyChanged}" />
<Button Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" Width="40" Height="20" Margin="10,0,0,0" Content="Find" Click="Find_Click" />
<Button Grid.Row="1" Grid.Column="1" HorizontalAlignment="Left" VerticalAlignment="Center" Width="50" Height="20" Margin="70,0,0,0" Content="Refund" Click="Refund_Click" />
<TextBlock Grid.Row="3" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,100,0" Text="OrderID:"/>
<TextBlock Grid.Row="4" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,100,0" Text="Customer:"/>
<TextBlock Grid.Row="5" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,100,0" Text="Product:"/>
<TextBlock Grid.Row="6" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,100,0" Text="Branch:"/>
<TextBlock Grid.Row="7" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,100,0" Text="Sales Price:"/>
<TextBlock Grid.Row="8" Grid.Column="0" HorizontalAlignment="Right" VerticalAlignment="Center" Margin="0,0,100,0" Text="Quantity:"/>
<TextBlock Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="200" Margin="30,0,0,0" Text="{Binding Path=Order.OrderID, Mode=TwoWay}"/>
<TextBlock Grid.Row="4" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="200" Margin="30,0,0,0" Text="{Binding Path=Order.Customer.FullName, Mode=TwoWay}"/>
<TextBlock Grid.Row="5" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="200" Margin="30,0,0,0" Text="{Binding Path=Order.Product.ProductName, Mode=TwoWay}"/>
<TextBlock Grid.Row="6" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="200" Margin="30,0,0,0" Text="{Binding Path=Order.Branch.BranchName, Mode=TwoWay}"/>
<TextBlock Grid.Row="7" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="200" Margin="30,0,0,0" Text="{Binding Path=Order.SalesPrice, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"/>
<TextBlock Grid.Row="8" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="200" Margin="30,0,0,0" Text="{Binding Path=Order.Stocks, Mode=TwoWay}"/>
<Button Grid.Row="10" Grid.Column="0" Grid.ColumnSpan="2" HorizontalAlignment="Center" VerticalAlignment="Center" Width="60" Height="25" Content="Cancel" Command="{x:Static NavigationCommands.BrowseBack}" />
</Grid>
</Page>
Keep in mind that I've literally learned everything I know about data binding in the last 48 hours so bear with me here.
Any kind of help at all is very much appreciated. Thank!
You need to implement INotifyPropertyChanged in Orders class.
You need to Invoke OnPropertyChanged() inside all setters.
Where your view model is getting instantiated ? I guess since you are recreating your viewmodel instance in ModifyOrder class
boundData = new ViewModel();
binding is lost and may be because of that its not showing up .
...Yeah, so. It was the
public ViewModel()
{
Order = new Order();
}
that was wiping clean the private static Orders _Order in the ViewModel class every time it was instantiated so I changed it to
public ViewModel()
{
if (_Order == null)
{
Order = new Order();
}
}
and that fixed the problem...
Thanks to everyone that helped me out with this! I learned a lot from you all!
I'm going to go cry myself to sleep now <3
I have done opening the modal dialog in Wpf MVVM. But I am new to prism. I have tried the following code in MVVM. Now its working fine. But I want to do the same concept using prism with ribbon window. In the below code I have not used ribbon window, instead of ribbon window I used the button. please refer the below code,
MainWindow.xaml
<Window.Resources>
<DataTemplate DataType="{x:Type vm:ModalDialogViewModel}">
<view:ModalDialog />
</DataTemplate>
</Window.Resources>
<Grid>
<Grid HorizontalAlignment="Stretch" VerticalAlignment="Center">
<Grid>
<Button
Width="150"
Height="25"
Margin="0,10,0,0"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Command="{Binding Path=LoadViewCommand}"
Content="Show Modal Dialog" />
</Grid>
</Grid>
<Grid Visibility="{Binding IsCloseModalWindow, Converter={StaticResource BooleanToVisibilityConverter}}">
<Border Background="#90000000">
<Border
HorizontalAlignment="Center"
VerticalAlignment="Center"
Background="White"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="0">
<Border.BitmapEffect>
<DropShadowBitmapEffect
Direction="270"
Opacity="0.5"
ShadowDepth="0.7"
Color="Black" />
</Border.BitmapEffect>
<ContentControl Content="{Binding Path=CurrentViewModel}" />
</Border>
</Border>
</Grid>
</Grid>
MainWindowViewModel
public class MainWindowViewModel : ViewModelBase, ICloseWindow
{
private ICommand loadViewCommand;
private ViewModelBase _currentViewModel;
public ViewModelBase CurrentViewModel
{
get { return _currentViewModel; }
set
{
_currentViewModel = value;
this.OnPropertyChanged("CurrentViewModel");
}
}
private bool isCloseModalWindow = false;
public bool IsCloseModalWindow
{
get { return isCloseModalWindow; }
set { isCloseModalWindow = value; OnPropertyChanged("IsCloseModalWindow"); }
}
public MainWindowViewModel()
{
}
public ICommand LoadViewCommand => loadViewCommand ?? (loadViewCommand = new RelayCommand(showView, canShowView));
private void showView(object obj)
{
IsCloseModalWindow = true;
CurrentViewModel = new ModalDialogViewModel(new ModalDialogModel() { Name = "New Modal Window" }, this);
}
private bool canShowView(object obj)
{
return true;
}
public void closeWindow()
{
IsCloseModalWindow = false;
}
}
ModalDialog
<Grid MinWidth="300" Background="White">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid
Grid.Row="0"
MinHeight="30"
Background="SkyBlue">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Button
Grid.Column="1"
Width="40"
Height="25"
Content="X"
BorderThickness="0"
Background="Transparent"
Foreground="White"
Margin="0,0,5,0"
HorizontalAlignment="Right"
VerticalAlignment="Center"
Command="{Binding CancelCommand}"
CommandParameter="{Binding ElementName=modalDialog}"
ToolTip="Close" />
</Grid>
</Grid>
<Grid Grid.Row="1" Margin="15">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="*" />
</Grid.ColumnDefinitions>
<Label
Grid.Row="0"
Grid.Column="0"
Content="Name"
Style="{StaticResource commonMargin}" />
<Label
Grid.Row="0"
Grid.Column="1"
Content=":"
Style="{StaticResource commonMargin}" />
<TextBox
Grid.Row="0"
Grid.Column="2"
Width="100"
Text="{Binding Path=Name}"
Style="{StaticResource commonTimerMargin}" />
</Grid>
<Grid
Grid.Row="2"
Margin="0,0,15,10"
HorizontalAlignment="Right">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Button
Grid.Column="0"
Width="80"
Height="30"
Margin="0,0,10,0"
Background="White"
Command="{Binding CancelCommand}"
CommandParameter="{Binding ElementName=modalDialog}"
Content="CANCEL" />
<Button
Grid.Column="1"
Width="80"
Height="30"
Background="SkyBlue"
Command="{Binding ApplyCommand}"
CommandParameter="{Binding ElementName=modalDialog}"
Content="APPLY"
Foreground="White" />
</Grid>
</Grid>
ModalDialogViewModel
public class ModalDialogViewModel : ViewModelBase
{
private ICommand cancelCommand;
public ModalDialogModel Model { get; private set; }
private ICloseWindow _closeWindow;
public ModalDialogViewModel(ModalDialogModel modalDialogModel, ICloseWindow closeWindow)
{
this.Model = modalDialogModel;
this._closeWindow = closeWindow;
}
public ICommand CancelCommand => cancelCommand ?? (cancelCommand = new RelayCommand(CloseWindow, CanCloseWindow));
private void CloseWindow(object obj)
{
_closeWindow.closeWindow();
}
private bool CanCloseWindow(object obj)
{
return true;
}
}
My Requirement is when user click the ribbon window button the modal dialog is open. The Shell window is a ribbon window. I have added HomeTab module and many other modules as separate class library.
You can do it like this in .xaml:
xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
xmlns:prism="http://prismlibrary.com/"
<i:Interaction.Triggers>
<prism:InteractionRequestTrigger SourceObject="{Binding PopUpDialogActionBinding}"> '<-- Here is your action binding
<prism:PopupWindowAction IsModal="True" CenterOverAssociatedObject="False">
<prism:PopupWindowAction.WindowStyle>
<Style TargetType="Window">
<Setter Property="Icon" Value="IconPath"/>
<Setter Property="Height" Value="400"/>
<Setter Property="Width" Value="400"/>
</Style>
</prism:PopupWindowAction.WindowStyle>
<prism:PopupWindowAction.WindowContent>
<views:YourCustomView /> ' <--- Put your view into the dialog
</prism:PopupWindowAction.WindowContent>
</prism:PopupWindowAction>
</prism:InteractionRequestTrigger>
</i:Interaction.Triggers>
<Grid>
...
</Grid>
I did it as in the example 28:
https://github.com/PrismLibrary/Prism-Samples-Wpf
I'm writing my first program with the use wpf and mvvm.
Have a problem, that in the case of changes data in fields of selecteditem, selecting a new item becomes impossible.
If add to listview attribute SelectionMode="Single", then if many times try pick item, exeption:
The element with the same key has already been added.
image: https://www.dropbox.com/s/ey7izl19803uuhc/1.png
If this attribute is removed, then pick another item, simply does not occur.
Image: https://dl.dropboxusercontent.com/u/32438899/2.png
If the data has not changed, the navigation works fine.
XAML code:
<?xml version="1.0" encoding="utf-8" ?>
<Window x:Class="MHConfigurator.Views.MainView"
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:DataContext="{Binding Path=MainViewModel}"
Title="Редактирование шаблонов писем" Height="Auto" Width="1000" MinWidth="1000" MinHeight="400">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"></RowDefinition>
<RowDefinition></RowDefinition>
<RowDefinition Height="Auto"></RowDefinition>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" Margin="7">
<TextBlock DockPanel.Dock="Left" Margin="5,5,2,5" HorizontalAlignment="Left">Поиск:</TextBlock>
<TextBox DockPanel.Dock="Right" Margin="2,2,2,2" HorizontalAlignment="Stretch" Text="{Binding SearchString, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"></TextBox>
</DockPanel>
<ListView Grid.Row="1" ItemsSource="{Binding Path=MailProperties, Mode=TwoWay}" Width="Auto" HorizontalAlignment="Stretch"
VerticalAlignment="Stretch" Margin="5" SelectedItem="{Binding Path=CurrentProperty, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" >
<ListView.View>
<GridView>
<GridViewColumn DisplayMemberBinding="{Binding ButtonID, Mode=TwoWay}" Header="ID шаблона" Width="Auto" />
<GridViewColumn DisplayMemberBinding="{Binding Description, Mode=TwoWay}" Header="Описание" Width="Auto" />
</GridView>
</ListView.View>
</ListView>
<Grid VerticalAlignment="Center" Grid.Row="2" DataContext="{Binding CurrentProperty}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="250"></ColumnDefinition>
<ColumnDefinition></ColumnDefinition>
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
<RowDefinition Height="*"></RowDefinition>
</Grid.RowDefinitions>
<DockPanel Grid.Row="0" Grid.Column="0">
<TextBlock DockPanel.Dock="Left" Margin="5,5,2,5" VerticalAlignment="Center" HorizontalAlignment="Left">ID шаблона:</TextBlock>
<TextBox DockPanel.Dock="Right" Margin="2,2,2,2" VerticalAlignment="Center" HorizontalAlignment="Stretch"
VerticalContentAlignment="Center" Text="{Binding ButtonID}"></TextBox>
</DockPanel>
<DockPanel Grid.Row="1" Grid.Column="0">
<CheckBox DockPanel.Dock="Left" HorizontalAlignment="Left" Margin="5" VerticalAlignment="Center" IsChecked="{Binding FillSubject}">Заполнять тему</CheckBox>
</DockPanel>
<DockPanel Grid.Row="2" Grid.Column="0">
<CheckBox DockPanel.Dock="Left" HorizontalAlignment="Left" Margin="5" VerticalAlignment="Center" IsChecked="{Binding FillTO}">Заполнять адресатов</CheckBox>
</DockPanel>
<DockPanel Grid.Row="3" Grid.Column="0">
<CheckBox DockPanel.Dock="Left" HorizontalAlignment="Left" Margin="5" VerticalAlignment="Center" IsChecked="{Binding FillCopy}">Заполнять копию</CheckBox>
</DockPanel>
<DockPanel Grid.Row="4" Grid.Column="0">
<CheckBox DockPanel.Dock="Left" HorizontalAlignment="Left" Margin="5" VerticalAlignment="Center" IsChecked="{Binding FillHideCopy}">Заполнять скрытую копию</CheckBox>
</DockPanel>
<DockPanel Grid.Row="5" Grid.Column="0">
<CheckBox DockPanel.Dock="Left" HorizontalAlignment="Left" Margin="5" VerticalAlignment="Center" IsChecked="{Binding HighImportance}">Высокая важность</CheckBox>
</DockPanel>
<DockPanel Grid.Row="0" Grid.Column="1">
<TextBlock DockPanel.Dock="Left" VerticalAlignment="Center" Margin="10,5,2,5" Width="115" >Описание шаблона:</TextBlock>
<TextBox DockPanel.Dock="Left" Margin="2,2,5,2" TextWrapping="Wrap" VerticalContentAlignment="Center" Text="{Binding Description}"></TextBox>
</DockPanel>
<DockPanel Grid.Row="1" Grid.Column="1">
<TextBlock DockPanel.Dock="Left" VerticalAlignment="Center" Margin="10,5,2,5" Width="115">Тема письма:</TextBlock>
<TextBox DockPanel.Dock="Left" Margin="2,2,5,2" TextWrapping="Wrap" VerticalContentAlignment="Center" Text="{Binding Subject}"></TextBox>
</DockPanel>
<DockPanel Grid.Row="2" Grid.Column="1">
<TextBlock DockPanel.Dock="Left" VerticalAlignment="Center" Margin="10,5,2,5" Width="115">Адресаты:</TextBlock>
<TextBox DockPanel.Dock="Left" Margin="2,2,5,2" TextWrapping="Wrap" VerticalContentAlignment="Center" Text="{Binding TO}"></TextBox>
</DockPanel>
<DockPanel Grid.Row="3" Grid.Column="1">
<TextBlock DockPanel.Dock="Left" VerticalAlignment="Center" Margin="10,5,2,5" Width="115">Копия:</TextBlock>
<TextBox DockPanel.Dock="Left" Margin="2,2,5,2" TextWrapping="Wrap" VerticalContentAlignment="Center" Text="{Binding Copy}"></TextBox>
</DockPanel>
<DockPanel Grid.Row="4" Grid.Column="1">
<TextBlock DockPanel.Dock="Left" VerticalAlignment="Center" Margin="10,5,2,5" Width="115">Скрытая копия:</TextBlock>
<TextBox DockPanel.Dock="Left" Margin="2,2,5,2" TextWrapping="Wrap" VerticalContentAlignment="Center" Text="{Binding HideCopy}"></TextBox>
</DockPanel>
<DockPanel Grid.Row="5" Grid.Column="1">
<CheckBox DockPanel.Dock="Left" VerticalAlignment="Center" HorizontalAlignment="Center" Margin="5">Напоминание</CheckBox>
<TextBlock DockPanel.Dock="Left" VerticalAlignment="Center" Margin="4">Время напоминания:</TextBlock>
<TextBox DockPanel.Dock="Left" Margin="2,2,5,2" VerticalContentAlignment="Center"></TextBox>
</DockPanel>
<DockPanel Grid.Row="6" Grid.Column="1">
<CheckBox DockPanel.Dock="Left" VerticalAlignment="Center" HorizontalAlignment="Left" Margin="5">Заполнять текст письма</CheckBox>
</DockPanel>
<DockPanel Grid.Row="7" Grid.Column="0" Grid.ColumnSpan="2">
<Button DockPanel.Dock="Left" Margin="15" HorizontalAlignment="Left" VerticalAlignment="Center" Width="150" Height="40">Добавить новый шаблон</Button>
<Button DockPanel.Dock="Left" Margin="15" HorizontalAlignment="Left" VerticalAlignment="Center" Width="150" Height="40">Сохранить</Button>
<Button DockPanel.Dock="Left" Margin="15" HorizontalAlignment="Left" VerticalAlignment="Center" Width="150" Height="40">Отмена</Button>
<TextBlock DockPanel.Dock="Left" Margin="0,4,4,4" VerticalAlignment="Center">Заметка:</TextBlock>
<TextBox DockPanel.Dock="Right" Margin="5" TextWrapping="Wrap" AcceptsReturn="True" Height="70" HorizontalAlignment="Stretch" VerticalScrollBarVisibility="Visible"
SpellCheck.IsEnabled="True" Language="ru-ru"></TextBox>
</DockPanel>
</Grid>
</Grid>
</Window>
In viewmodel problems can not be. It is very easy, PropertyChanged called whenever necessary.
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Collections.Specialized;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using MugenMvvmToolkit;
using MugenMvvmToolkit.ViewModels;
using MugenMvvmToolkit.Models;
using System.Windows.Input;
using MHConfigurator.Models;
using System.Windows;
namespace MHConfigurator.ViewModels
{
class MainViewModel : ViewModelBase
{
public MainViewModel()
{
_mailProperties = new ObservableCollection<MailProperty>(DAL.GetDAL().MailPropertys);
//MailsTemplates = DAL.GetDAL().GetEmptyMailTemplates();
}
#region Fields
#region Backing Fields
private ObservableCollection<MailProperty> _mailProperties;
private MailProperty _currentProperty;
private string _searchString;
private MailProperty _originalCurrentProperty;
private bool _currentPropertyChanged = false;
private List<MailsTemplate> _mailsTemplates;
private int _selectedMailTemplate;
#endregion
public string SearchString
{
get
{
if (_searchString.IsNullOrEmpty()) return "";
return _searchString;
}
set
{
bool stringContains = _searchString != null && value.Contains(_searchString);
_searchString = value;
CurrentProperty = null;
//Not matter
}
}
public ObservableCollection<MailProperty> MailProperties
{
get { return _mailProperties; }
set
{
_mailProperties = value;
//OnPropertyChanged(new PropertyChangedEventArgs("MailProperties"));
OnPropertyChanged();
}
}
public MailProperty CurrentProperty
{
get { return _currentProperty; }
set
{/*
if ((_originalCurrentProperty != null)&&(_currentPropertyChanged)&&(_originalCurrentProperty!=_currentProperty)) //Если выбран другой объект и есть несохранённые изменения
{
MessageBoxResult result = MessageBox.Show("Есть несохранённые изменения. Сохранить?", "Несохранённые изменения", MessageBoxButton.YesNo, MessageBoxImage.Question);
if (result == MessageBoxResult.Yes)
{
}
else
{
MailProperties[MailProperties.IndexOf(_currentProperty)] = _originalCurrentProperty; //Находим в коллекции изменённый объект и заменить его оригиналом
}
}
_originalCurrentProperty = Helper.DeepClone(_currentProperty); //Делаем резервную копию
SelectedMailTemplate = value.BodyID; //выставляем id шаблона
*/
_currentProperty = value;
// OnPropertyChanged(new PropertyChangedEventArgs("CurrentProperty"));
OnPropertyChanged();
}
}
public List<MailsTemplate> MailsTemplates
{
get { return _mailsTemplates; }
set
{
_mailsTemplates = value;
OnPropertyChanged();
}
}
public int SelectedMailTemplate
{
get { return _selectedMailTemplate; }
set
{
_selectedMailTemplate = value;
CurrentProperty.BodyID = value;
OnPropertyChanged();
}
}
#endregion
#region Commands
public ICommand NewCommand { get; private set; }
public ICommand SaveCommand { get; private set; }
public ICommand CancelCommand { get; private set; }
#region Execute
#endregion
#region CanExecute
#endregion
#endregion
}}
I have no idea.
I will be glad to any ideas.
P.S.: Sorry for my bad english.