簡體   English   中英

將可寫 bitmap 綁定到 canvas

[英]Binding Writeable bitmap to canvas

我正在嘗試編寫一個簡單的 WPF 程序來實現康威的生命游戲。 我的 Window 由一個工具欄和一個帶有嵌入圖像的 canvas 組成,我試圖在其上顯示一個可寫的 bitmap。

我在工具欄上有一個按鈕,單擊該按鈕時會更新一代,然后在 canvas 圖像上顯示生成的 bitmap。 我直接用

img.Source = wbmp;

這沒有問題。

但是,我想顯示正在進行的更新,而不必每次都單擊“更新”按鈕。 所以我嘗試實現一個 10 次迭代的循環。 但是,更新后的圖像僅在第 10 次迭代完成后顯示(即我沒有看到前 9 代)

我的理解是,我需要將 Image 控件綁定到 Writeable bitmap 以便“強制”每一代更新。 我已經用下面的代碼試過了——但現在什么都沒有顯示。 最初我發現 PropertyChanged 事件似乎沒有被觸發,但我沒有分配任何方法,所以我添加了 PropertyChanged = delegate {} ; (我這樣做是因為互聯網告訴我這樣做!)

我真的不確定我要去哪里錯了。 我對 WPF 尤其是綁定一無所知。 (我的大部分代碼都是改編的復制面食。)任何幫助將不勝感激!

<Canvas Name ="canvas" Grid.Row="1" Background="LightGray">
    <Image Name="img" Source="{Binding GoLImage}"/>
</Canvas>

public class MyViewModel : INotifyPropertyChanged
{
    public event PropertyChangedEventHandler PropertyChanged = delegate { };
    private ImageSource golImage;  //writeable bitmap;

    public ImageSource GoLImage
    {
        get { return golImage; }
        set
        {
            golImage = value;
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(GoLImage)));
        }
    }

}

 private void Button_Run10_Click(object sender, RoutedEventArgs e)
    {
        BitmapPixelMaker bmp = new BitmapPixelMaker(1200, 800);
        for (int i = 0; i < 10; i++)
        {
            goL.UpdateLifeGrid();  //goL is an instance of my class implementing the Game of Life
            goL.LifeGridTobmp(bmp);
            WriteableBitmap wbmp = bmp.MakeBitmap(96, 96);

            //Trying to display bitmap
            MyViewModel golDisplay = new MyViewModel();
            golDisplay.GoLImage = wbmp; //This doesn't automatically display on each iteration

        }
    }

Button Click 處理程序中的for循環會阻塞 UI 線程。 而且您還沒有將視圖 model 實例分配給視圖的 DataContext 屬性。

將 DispatcherTimer 與 Tick 事件處理程序一起使用,如下所示。

不要在每個循環中創建新的視圖 model 實例和新的 WriteableBitmap,而只需修改現有的 - 因此您應該將視圖 model 屬性聲明更改為public WriteableBitmap GoLImage ,以便 ModifyBitmap 方法可以訪問它。

private readonly MyViewModel golDisplay = new MyViewModel();

private readonly DispatcherTimer timer = new DispatcherTimer
{
    Interval = TimeSpan.FromSeconds(0.1)
};

public MainWindow()
{
    InitializeComponent();

    golDisplay.GoLImage = WriteableBitmap(1200, 800, 96, 96, PixelFormats.Default, null);
    DataContext = golDisplay;

    timer.Tick += OnTimerTick;
    timer.Start(); // optionally, call Start/Stop in a Button Click handler
}

private void OnTimerTick(object sender, EventArgs e)
{
    var bmp = new BitmapPixelMaker(1200, 800);

    goL.UpdateLifeGrid();
    goL.LifeGridTobmp(bmp);

    ModifyBitmap(bmp); // write directly to golDisplay.GoLImage
}

DispatcherTimer 的替代方案可能是對異步和等待更新調用的簡單循環。

如下所示,Update 方法將執行 CPU 密集型計算,然后返回新的像素緩沖區

private async void OnWindowLoaded(object sender, RoutedEventArgs e)
{
    while (true)
    {
        var buffer = await Task.Run(() => game.Update());

        bitmap.WritePixels(new Int32Rect(0, 0, game.Width, game.Height),
                           buffer, game.Stride, 0);
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM