[英]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.