强制更新绑定到 InkCanvas 的控件
Force an update to a control that's bound to the InkCanvas
我有以下 XAML:
<Image Visibility="Visible"
Source="{Binding ElementName=inkCanvas,
Converter={StaticResource InkCanvasToImageSource},
UpdateSourceTrigger=PropertyChanged}">
</Image>
<InkCanvas x:Name="inkCanvas" />
我要做的是将 InkCanvas Stroke Collection 转换为 BitmapImage。我正在使用 MVVM,并希望通过命令执行此操作。我遇到的问题是上面的代码不会触发转换器触发。我正在使用 UWP,所以我只能将其中一个控件作为命令参数传递。
我需要一种方法将一种方法转换为另一种方法,但我想在 ViewModel 中进行。
InkCanvas
控件与 InkPresenter
object (exposed through the InkPresenter
属性) 的实例相关联。 InkPresenter
提供用于管理 InkCanvas
控件的墨迹数据的输入、处理和呈现的属性、方法和事件。因此绑定到 InkCanvas
不会触发您的转换器,因为墨水输入完全由 InkPresenter
管理。而且InkCanvas.InkPresenter
属性不是依赖属性,我们不能绑定到这个属性。所以我们不能强制 Image
更新绑定到 InkCanvas
。我们必须在代码隐藏中执行此操作,这可能会破坏 MVVM 设计。
要更新 Image
,我们可以使用 StrokesCollected
和 StrokesErased
事件来检测墨水输入,并在这些事件中将所有 InkStroke
对象保存到 BitmapImage
.例如:
在XAML
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Image x:Name="MyImage" />
<Border Grid.Row="1" BorderBrush="Red" BorderThickness="2">
<InkCanvas x:Name="inkCanvas" />
</Border>
</Grid>
在代码隐藏中:
public MainPage()
{
this.InitializeComponent();
...
inkCanvas.InkPresenter.StrokesCollected += InkPresenter_StrokesCollected;
inkCanvas.InkPresenter.StrokesErased += InkPresenter_StrokesErased;
}
private async void InkPresenter_StrokesErased(InkPresenter sender, InkStrokesErasedEventArgs args)
{
var image = await SaveAsync();
MyImage.Source = image;
}
private async void InkPresenter_StrokesCollected(InkPresenter sender, InkStrokesCollectedEventArgs args)
{
var image = await SaveAsync();
MyImage.Source = image;
}
private async Task<BitmapImage> SaveAsync()
{
var bitmap = new BitmapImage();
if (inkCanvas.InkPresenter.StrokeContainer.GetStrokes().Count > 0)
{
try
{
using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
{
await inkCanvas.InkPresenter.StrokeContainer.SaveAsync(stream);
stream.Seek(0);
bitmap.SetSource(stream);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex);
}
}
return bitmap;
}
这里我只是将图片设置为MyImage
,你也可以将其设置为你的ViewModel并在Image
中使用Binding
。
我有以下 XAML:
<Image Visibility="Visible"
Source="{Binding ElementName=inkCanvas,
Converter={StaticResource InkCanvasToImageSource},
UpdateSourceTrigger=PropertyChanged}">
</Image>
<InkCanvas x:Name="inkCanvas" />
我要做的是将 InkCanvas Stroke Collection 转换为 BitmapImage。我正在使用 MVVM,并希望通过命令执行此操作。我遇到的问题是上面的代码不会触发转换器触发。我正在使用 UWP,所以我只能将其中一个控件作为命令参数传递。
我需要一种方法将一种方法转换为另一种方法,但我想在 ViewModel 中进行。
InkCanvas
控件与 InkPresenter
object (exposed through the InkPresenter
属性) 的实例相关联。 InkPresenter
提供用于管理 InkCanvas
控件的墨迹数据的输入、处理和呈现的属性、方法和事件。因此绑定到 InkCanvas
不会触发您的转换器,因为墨水输入完全由 InkPresenter
管理。而且InkCanvas.InkPresenter
属性不是依赖属性,我们不能绑定到这个属性。所以我们不能强制 Image
更新绑定到 InkCanvas
。我们必须在代码隐藏中执行此操作,这可能会破坏 MVVM 设计。
要更新 Image
,我们可以使用 StrokesCollected
和 StrokesErased
事件来检测墨水输入,并在这些事件中将所有 InkStroke
对象保存到 BitmapImage
.例如:
在XAML
<Grid Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Grid.RowDefinitions>
<RowDefinition />
<RowDefinition />
</Grid.RowDefinitions>
<Image x:Name="MyImage" />
<Border Grid.Row="1" BorderBrush="Red" BorderThickness="2">
<InkCanvas x:Name="inkCanvas" />
</Border>
</Grid>
在代码隐藏中:
public MainPage()
{
this.InitializeComponent();
...
inkCanvas.InkPresenter.StrokesCollected += InkPresenter_StrokesCollected;
inkCanvas.InkPresenter.StrokesErased += InkPresenter_StrokesErased;
}
private async void InkPresenter_StrokesErased(InkPresenter sender, InkStrokesErasedEventArgs args)
{
var image = await SaveAsync();
MyImage.Source = image;
}
private async void InkPresenter_StrokesCollected(InkPresenter sender, InkStrokesCollectedEventArgs args)
{
var image = await SaveAsync();
MyImage.Source = image;
}
private async Task<BitmapImage> SaveAsync()
{
var bitmap = new BitmapImage();
if (inkCanvas.InkPresenter.StrokeContainer.GetStrokes().Count > 0)
{
try
{
using (InMemoryRandomAccessStream stream = new InMemoryRandomAccessStream())
{
await inkCanvas.InkPresenter.StrokeContainer.SaveAsync(stream);
stream.Seek(0);
bitmap.SetSource(stream);
}
}
catch (Exception ex)
{
System.Diagnostics.Debug.WriteLine(ex);
}
}
return bitmap;
}
这里我只是将图片设置为MyImage
,你也可以将其设置为你的ViewModel并在Image
中使用Binding
。