Используйте привязки команд для кнопки сохранения, затем вы можете включить / отключить кнопку в зависимости от вашего текущего состояния
см. простое учебное пособие и, если вам нужно более подробное объяснение статья MSDN , Джош Смит также получает более подробную информацию
Мы справимся с вышеуказанной ситуацией, используя комбинацию команд и свойство IsValid в базовой модели, к которой мы привязываем. Мы выполняем проверку на уровне бизнес-модели (также иногда в пользовательском интерфейсе), и когда бизнес-модель действует, мы включаем команду или, как в вашем случае, кнопку сохранения.
Вот пример стиля, который мы применяем к нашим текстовым полям (мы производим от текстового поля и присваиваем ему другое свойство, называемое SimpleField. Это поле имеет свойства IsValid, IsDirty, IsReadOnly, ErrorMessage и DatabaseValue. Это позволяет нам знать если поле действительно, изменилось ли оно, если оно доступно только для чтения (т. е. у пользователя нет разрешения на изменение значения или оно заблокировано по другой причине), если есть сообщение об ошибке (связанное со свойством IsValid) и также значение базы данных (для случая, когда поле изменилось, пользователь может видеть исходное значение). Мы используем все эти свойства в стиле ниже
<!-- Simple TextBox -->
<Style
TargetType="{x:Type local:SimpleFieldTextBox}"
BasedOn="{StaticResource {x:Type TextBox}}">
<Setter
Property="KeyboardNavigation.TabNavigation"
Value="None" />
<Setter
Property="FocusVisualStyle"
Value="{x:Null}" />
<Setter
Property="AllowDrop"
Value="True" />
<Setter
Property="SnapsToDevicePixels"
Value="True" />
<Setter
Property="Height"
Value="22" />
<Setter
Property="Template">
<Setter.Value>
<ControlTemplate
TargetType="{x:Type local:SimpleFieldTextBox}">
<Border
x:Name="PART_SimpleFieldTextBox"
Background="{TemplateBinding Background}"
BorderBrush="{TemplateBinding BorderBrush}"
BorderThickness="{TemplateBinding BorderThickness}"
Height="{TemplateBinding Height}"
SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="Auto" />
<ColumnDefinition
Width="*" />
</Grid.ColumnDefinitions>
<!-- The implementation places the Content into the ScrollViewer.
It must be named PART_ContentHost for the control to function -->
<ScrollViewer
x:Name="PART_ContentHost"
Grid.Column="1"
Margin="0" />
<!-- Not Valid Icon -->
<Path
x:Name="IconError"
Grid.Column="0"
Fill="Red"
Stretch="Fill"
Margin="1,1,4,1"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Visibility="Collapsed"
Width="4"
Height="14"
SnapsToDevicePixels="True"
Data="M0,11 L6,11 6,14 0,14 z M0,0 L6,0 6,10 0,10 z">
<Path.ToolTip>
<ToolTip>
<StackPanel
Orientation="Vertical"
MaxWidth="300"
MaxHeight="100">
<TextBlock
FontStyle="Italic"
Text="Error:" />
<TextBlock
Margin="8,0,0,0"
TextWrapping="WrapWithOverflow"
TextTrimming="CharacterEllipsis"
Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SimpleField.ErrorMessage}" />
<TextBlock
Margin="0,4,0,0"
FontStyle="Italic"
Text="Original Value: " />
<TextBlock
Margin="8,0,0,0"
TextWrapping="WrapWithOverflow"
TextTrimming="CharacterEllipsis"
Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SimpleField.DatabaseValue}" />
</StackPanel>
</ToolTip>
</Path.ToolTip>
</Path>
<!-- Valid (but changed) Icon-->
<Path
x:Name="IconWarning"
Grid.Column="0"
Fill="#FF5BBD30"
Stretch="Fill"
Margin="1,1,0,0"
HorizontalAlignment="Left"
VerticalAlignment="Top"
Visibility="Collapsed"
Width="8"
Height="8"
SnapsToDevicePixels="True"
Data="M0,0 L8,0 0,8 z">
<Path.ToolTip>
<ToolTip>
<StackPanel
Orientation="Vertical"
MaxWidth="500"
MaxHeight="100">
<TextBlock
Text="Original Value: " />
<TextBlock
Margin="8,0,0,0"
TextWrapping="Wrap"
TextTrimming="CharacterEllipsis"
Text="{Binding RelativeSource={RelativeSource TemplatedParent}, Path=SimpleField.DatabaseValue}" />
</StackPanel>
</ToolTip>
</Path.ToolTip>
</Path>
</Grid>
</Border>
<ControlTemplate.Triggers>
<!-- Stop the text box being edited if the simple field is read only -->
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource Self}, Path=SimpleField.IsReadOnly}"
Value="True">
<Setter
Property="IsReadOnly"
Value="True" />
<Setter
Property="Foreground"
Value="{StaticResource DisabledForegroundBrush}" />
<Setter
TargetName="PART_SimpleFieldTextBox"
Property="Background"
Value="{StaticResource DisabledBackgroundBrush}" />
<Setter
TargetName="PART_SimpleFieldTextBox"
Property="BorderBrush"
Value="{StaticResource DisabledBorderBrush}" />
</DataTrigger>
<!-- IsEnabled condition -->
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource Self}, Path=IsEnabled}"
Value="False">
<Setter
Property="Foreground"
Value="{StaticResource DisabledForegroundBrush}" />
<Setter
TargetName="PART_SimpleFieldTextBox"
Property="Background"
Value="{StaticResource DisabledBackgroundBrush}" />
<Setter
TargetName="PART_SimpleFieldTextBox"
Property="BorderBrush"
Value="{StaticResource DisabledBorderBrush}" />
</DataTrigger>
<!-- When value inside field has been changed -->
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource Self}, Path=SimpleField.IsDirty}"
Value="True">
<Setter
TargetName="IconWarning"
Property="Visibility"
Value="Visible" />
</DataTrigger>
<!-- When value inside field is NOT valid -->
<DataTrigger
Binding="{Binding RelativeSource={RelativeSource Self}, Path=SimpleField.IsValid}"
Value="False">
<Setter
TargetName="IconWarning"
Property="Visibility"
Value="Collapsed" />
<Setter
TargetName="IconError"
Property="Visibility"
Value="Visible" />
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>