摘要:C# WPF Viewbox調整大小並且掌握UI長寬(Uniform時)(順便教擷取畫面)
這東西雖然簡單,但網路上很難找到!我爬了英文網站也幾乎無解~
原因就是Viewbox只是讓你"看起來"讓元件產生適應視窗大小的錯覺,但是他並非真正的修改了你的元件長寬。
所以當你希望在UI"看起來"不一樣大時做動作,只是用UI.width和UI.height你會瘋掉~
因為他一直都顯示你原本的UI大小!(PointToWindow我也嘗試過但都沒辦法)
所以為此我就做了變通了~
真正改變的會是ViewBox和Window,
我當初一直用Window做比對,結果沒想到Window會延伸這個道理......
總之,或許我的方法比較笨,可是確實解決了我的問題。
這個範例大概是:希望調整視窗大小後正確的擷取圖片(圖片是鎖定在一個範圍)
而那個鎖定範圍就是讓我頭大的東西~~~
(若是單純依照視窗大小還比較簡單)
首先,一定有個ViewBox在xaml,
而為了讓我們的元件可以一拖拉庫的放在viewBox裡,
我是讓viewBox裡包含一個grid(只是因為原本xaml就有grid,為了怕麻煩所以直接在xaml修改,將外圍包了viewbox)
類似這樣:
<Viewbox Name="viewbox1" Stretch="Uniform">
<Grid Width="1005" Height="714" Background="{x:Null}" Name="grids">
<隨便的元件們>
</隨便的元件們>
</Grid>
</Viewbox>
因為我將grid和viewbox拉一樣大,所以用grid大小代替viewbox大小。
接著,在視窗改變的時候加入這樣的程式碼:
private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
{
double aheight = this.viewbox1.ActualHeight;
double awidth = this.viewbox1.ActualWidth;
if ((aheight < 714 && awidth > 1005 && aheight <= awidth) || (aheight > 714 && awidth > 1005 && aheight <= awidth))
{
double width = ((1005 * aheight) / 714);
string size = width + ";" + aheight;
StreamWriter file = new StreamWriter(System.IO.Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + "\\size.txt");
file.Write(size);
file.Close();
}
else
{
double height = ((714 * awidth) / 1005);
string size = awidth + ";" + height;
StreamWriter file = new StreamWriter(System.IO.Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + "\\size.txt");
file.Write(size);
file.Close();
}
}
總而言之,就是在改變視窗大小時將ViewBox的尺寸記錄下來(存起來)。
記得,此處的viewBox是Uniform模式,我也做出了Fill模式,但是Fill比較簡單,就請自己依樣畫葫蘆啦~
中間的if條件式是根據長方型理論以及比例理論得出的結果來固定寬或是固定高。
因為我的範圍一定是長大於寬才會那樣判斷。
(可自行嘗試畫真值表→
actualH->aH, actualW->aW, originH->oH, originW->oW
aH>oH且aW>oW且aH>aW......以此類推,其中有兩條基本上是不可能存在的長方形)
接著,在某個"拍照"按鈕裡加上這樣的程式碼:
private void btnCapture_MouseDown(object sender, MouseButtonEventArgs e)
{
double windowH = 0;
double windowW = 0;
#region window size
try
{
string path = System.IO.Path.GetDirectoryName(Process.GetCurrentProcess().MainModule.FileName) + "\\size.txt";
if (System.IO.File.Exists(path)) //若檔案存在
{
StreamReader stream = new StreamReader(path, System.Text.Encoding.Default);
string ss = stream.ReadToEnd();
char[] ds = { ';' };
string[] temp = ss.Split(ds);
string wid = temp[0];
string hei = temp[1];
windowW = Convert.ToDouble(wid);
windowH = Convert.ToDouble(hei);
stream.Close();
}
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
#endregion
Point video = border1.PointToScreen(new Point(0, 0));
int newH = (int)((windowH * 385) / 714);
int newW = (int)((windowW * 527) / 1005);
System.Drawing.Bitmap b = new System.Drawing.Bitmap(newW, newH);
using (System.Drawing.Graphics g = System.Drawing.Graphics.FromImage(b))
{
g.CopyFromScreen((int)video.X, (int)video.Y, (int)border1.Margin.Right, (int)border1.Margin.Bottom, b.Size, System.Drawing.CopyPixelOperation.SourceCopy);
}
Microsoft.Win32.SaveFileDialog dlg = new Microsoft.Win32.SaveFileDialog();
dlg.DefaultExt = ".png";
dlg.Filter = "JPeg Image|*.jpg|Bitmap Image|*.bmp|Gif Image|*.gif|PNG Image|*.png";
Nullable<bool> result = dlg.ShowDialog();
if (result == true)
{
string filename = dlg.FileName;
b.Save(filename);
}
}
哈,為了美觀我的不是按鈕是圖片充當按鈕啦~不過結果一樣~
其中border1是我想要拍照的範圍(因為不是全螢幕只有特定部分),
而385是寬、527是長。
看到這數字真是可恨呀Orz
因為之前用盡方法都是抓這個數值,
但我眼睛看到的他明明縮小了呀(果然眼見不能為憑)!
然後因為是Uniform,所以他一定是等比例!
記得他的比例是跟著ViewBox而不視窗!我那時就是跟著視窗跑害我的結果都不對!
所以newH和newW是那樣算的~
終於解決這個問題了~
感覺上蠻多人有這個困擾,
要是有更好的方法歡迎大家分享囉~
(我的腦袋真的要休息一下,這東西困擾我好久Orz)
還有一點!因為我的border1是動態加入的!
所以我那時還很懷疑要怎樣抓他的長寬Orz
所以如果你的元件是動態加入也不用怕喔~
(若是固定的元件應該也不會影響吧?)