强制更新绑定到 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,我们可以使用 StrokesCollectedStrokesErased 事件来检测墨水输入,并在这些事件中将所有 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