Về cơ bản nó đòi hỏi một viết lại hoàn toàn Canvas. Các giải pháp được đề xuất trước đây ghi đè MeasureOverride không thành công vì các thuộc tính mặc định Canvas.Left/.Top & c vô hiệu hóa Sắp xếp, nhưng CSONG cần phải làm mất hiệu lực biện pháp. (Lần đầu tiên bạn nhận được kích thước phù hợp, nhưng kích thước không thay đổi nếu bạn di chuyển các phần tử sau bố cục ban đầu).
Giải pháp Grid ít nhiều hợp lý nhưng ràng buộc với Lề để có được sự dịch chuyển x-y có thể phá hoại mã khác (particalary trong MVVM). Tôi đã vật lộn với giải pháp xem Grid trong một thời gian, nhưng các biến chứng với tương tác View/ViewModel và hành vi di chuyển cuối cùng đã khiến tôi thực hiện điều này. Đó là đơn giản và cho điểm, và chỉ cần làm việc.
Không phức tạp khi triển khai lại ArrangeOverride và MeasureOverride. Và bạn buộc phải viết ít nhất là nhiều mã ở nơi khác xử lý Grid/Margin ngu ngốc. Vì vậy, có bạn đang có.
Đây là giải pháp hoàn chỉnh hơn. hành vi ký quỹ khác không được kiểm tra. Nếu bạn cần bất cứ điều gì khác hơn là trái và đầu, thì điều này cung cấp một điểm khởi đầu, ít nhất.
CẢNH BÁO: Bạn phải sử dụng AutoResizeCanvas.Left và AutoResizeCanvas.Top các thuộc tính được đính kèm thay vì Canvas.Left và Canvas.Top. Các thuộc tính Canvas còn lại chưa được triển khai.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Mu.Controls
{
public class AutoResizeCanvas : Panel
{
public static double GetLeft(DependencyObject obj)
{
return (double)obj.GetValue(LeftProperty);
}
public static void SetLeft(DependencyObject obj, double value)
{
obj.SetValue(LeftProperty, value);
}
public static readonly DependencyProperty LeftProperty =
DependencyProperty.RegisterAttached("Left", typeof(double),
typeof(AutoResizeCanvas),
new FrameworkPropertyMetadata(0.0, OnLayoutParameterChanged));
private static void OnLayoutParameterChanged(
DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// invalidate the measure of the enclosing AutoResizeCanvas.
while (d != null)
{
AutoResizeCanvas canvas = d as AutoResizeCanvas;
if (canvas != null)
{
canvas.InvalidateMeasure();
return;
}
d = VisualTreeHelper.GetParent(d);
}
}
public static double GetTop(DependencyObject obj)
{
return (double)obj.GetValue(TopProperty);
}
public static void SetTop(DependencyObject obj, double value)
{
obj.SetValue(TopProperty, value);
}
public static readonly DependencyProperty TopProperty =
DependencyProperty.RegisterAttached("Top",
typeof(double), typeof(AutoResizeCanvas),
new FrameworkPropertyMetadata(0.0, OnLayoutParameterChanged));
protected override Size MeasureOverride(Size constraint)
{
Size availableSize = new Size(double.MaxValue, double.MaxValue);
double requestedWidth = MinimumWidth;
double requestedHeight = MinimumHeight;
foreach (var child in base.InternalChildren)
{
FrameworkElement el = child as FrameworkElement;
if (el != null)
{
el.Measure(availableSize);
Rect bounds, margin;
GetRequestedBounds(el,out bounds, out margin);
requestedWidth = Math.Max(requestedWidth, margin.Right);
requestedHeight = Math.Max(requestedHeight, margin.Bottom);
}
}
return new Size(requestedWidth, requestedHeight);
}
private void GetRequestedBounds(
FrameworkElement el,
out Rect bounds, out Rect marginBounds
)
{
double left = 0, top = 0;
Thickness margin = new Thickness();
DependencyObject content = el;
if (el is ContentPresenter)
{
content = VisualTreeHelper.GetChild(el, 0);
}
if (content != null)
{
left = AutoResizeCanvas.GetLeft(content);
top = AutoResizeCanvas.GetTop(content);
if (content is FrameworkElement)
{
margin = ((FrameworkElement)content).Margin;
}
}
if (double.IsNaN(left)) left = 0;
if (double.IsNaN(top)) top = 0;
Size size = el.DesiredSize;
bounds = new Rect(left + margin.Left, top + margin.Top, size.Width, size.Height);
marginBounds = new Rect(left, top, size.Width + margin.Left + margin.Right, size.Height + margin.Top + margin.Bottom);
}
protected override Size ArrangeOverride(Size arrangeSize)
{
Size availableSize = new Size(double.MaxValue, double.MaxValue);
double requestedWidth = MinimumWidth;
double requestedHeight = MinimumHeight;
foreach (var child in base.InternalChildren)
{
FrameworkElement el = child as FrameworkElement;
if (el != null)
{
Rect bounds, marginBounds;
GetRequestedBounds(el, out bounds, out marginBounds);
requestedWidth = Math.Max(marginBounds.Right, requestedWidth);
requestedHeight = Math.Max(marginBounds.Bottom, requestedHeight);
el.Arrange(bounds);
}
}
return new Size(requestedWidth, requestedHeight);
}
public double MinimumWidth
{
get { return (double)GetValue(MinimumWidthProperty); }
set { SetValue(MinimumWidthProperty, value); }
}
public static readonly DependencyProperty MinimumWidthProperty =
DependencyProperty.Register("MinimumWidth", typeof(double), typeof(AutoResizeCanvas),
new FrameworkPropertyMetadata(300.0,FrameworkPropertyMetadataOptions.AffectsMeasure));
public double MinimumHeight
{
get { return (double)GetValue(MinimumHeightProperty); }
set { SetValue(MinimumHeightProperty, value); }
}
public static readonly DependencyProperty MinimumHeightProperty =
DependencyProperty.Register("MinimumHeight", typeof(double), typeof(AutoResizeCanvas),
new FrameworkPropertyMetadata(200.0,FrameworkPropertyMetadataOptions.AffectsMeasure));
}
}
Tôi đã chuyển từ Canvas sang Grid và hoạt động sau khi chỉnh sửa. Tôi đã phải thực hiện hai thay đổi: (1) ở khắp mọi nơi mà tôi đã sử dụng để thiết lập thuộc tính đính kèm Canvas.Left và Canvas.Top, bây giờ tôi thiết lập các thuộc tính thông thường Margin.Left và Margin.Top (Margin.Right và Margin.Bottom có thể trái tại 0); (2) sử dụng HorizontalAlignment = "Left" và VerticalAlignment = "Top" trên mỗi phần tử trong Grid. Chế độ "Stretch" mặc định có thể khiến các phần tử kết thúc ở giữa khi lề là 0. – Qwertie
"Đối với trường hợp bạn muốn nội dung con được tự động thay đổi kích thước và căn chỉnh, tốt nhất là sử dụng phần tử Lưới". Nhưng câu hỏi ban đầu là về việc thay đổi kích thước Canvas, không phải là các phần tử con.Tôi nghĩ rằng giải pháp được cung cấp bởi illef dưới đây trả lời tốt hơn câu hỏi này và tránh thiết lập quá nhiều thuộc tính trên tất cả các phần tử con. Với câu trả lời của illef bạn chỉ cần thiết lập thuộc tính đính kèm Top và Left mà tôi nghĩ là một giải pháp neater. Một khi bạn đã xác định đối tượng Canvas mới thì đó là một giải pháp có thể tái sử dụng có thể được sử dụng ở nơi khác trong dự án của bạn. – MikeKulls
Vấn đề tôi có với điều này là khi kết xuất nó sẽ không điều khiển chồng lên nhau và chúng bị lúng túng khắp nơi, trừ khi tất nhiên tôi đang làm điều gì đó sai. Ngoài ra các giải pháp illef là tính toán sai cho một số lý do. –