如何使控件相应地移动/调整大小到WPF中的背景图像

时间:2016-01-05 16:26:27

标签: c# .net wpf xaml

我最近在WPF上做的并不多,所以决定做一些我可以使用的东西,所以首先我要尝试制作类似交互式的东西,以减少纸张的使用。所以这就是我正在做的事情,我扫描了原始表单,它以 .png 格式保存,我作为资源添加,然后通过以下方式将其设置为窗口的背景图像:

<Window.Background>
    <ImageBrush ImageSource="pictures/podstawowa_front.png" />
</Window.Background>

这完全正常,但现在在用户想要输入一些数据的地方,我想放置WPF控件,这也很好。当我想调整窗口大小时,问题就出现了,背景图像的大小与控件不同。我曾尝试使用不同的容器进行控制,但似乎都没有。同时从控件中删除了所有高度,宽度,对齐,并且只留下边距(因此它有一些起始位置)。

示例:

启动时 - 它或多或少处于正确的位置,大小相近:

Application startup

调整窗口大小后:

After resizing window

所以你可以看到我缩小了窗口,但是控制器收缩得更多而根本没有移动。

我试过谷歌搜索并寻找类似的问题,但几乎找不到任何东西,试图弄乱不同的容器,转换,但似乎没有什么工作,因为我喜欢它。 (我也试图坚持XAML

我可能可以通过使用大量嵌套容器来解决它,但我试图避免它,因为它似乎是一种矫枉过正,我想知道是否还有其他更快更优雅的方法。请随时在评论中询问其他详细信息。提前感谢任何提示。

XAML代码:

<Window x:Class="DnD.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="MainWindow" Height="768" Width="1366">
    <Window.Background>
        <ImageBrush ImageSource="pictures/basic_front.png" />
    </Window.Background>

    <Grid>
        <TextBox Margin="265,307,970,413" TextWrapping="Wrap" Text="TextBox" FontSize="10"/>
    </Grid>

</Window>

2 个答案:

答案 0 :(得分:3)

这是因为更改窗口大小时保证金保持不变。因此,当您减小窗口的宽度时,TextBox与左右边缘保持相同的距离。

如果你必须支持调整大小,你真的不能只用XAML做到这一点。如果你可以超越XAML,你可以将边距绑定到窗口的高度和宽度,并编写一个转换器来更改边距以正确定位TextBox。

如果您实际上不需要支持调整大小,只需将窗口的ResizeMode设置为NoResize。

在图像上定位控件的更好方法是使用Canvas而不是Grid,并将图像放在Canvas中而不是窗口背景中。然后可以使用Canvas属性将TextBox放置在图像上的适当位置,而不是使用Margin。这不会解决调整大小问题,但这样可以在调整窗口大小时将内容保留为原始大小。

答案 1 :(得分:0)

嗯,这不是100%我想要达到的目标,但这已经成为我设法做的事情(感谢 JNP 关于保证金绑定的提示)。基本上我正在做的是使用 multiconverter 进行边距绑定,同时将控件的起始位置作为 ConverterParameter 传递,边距取决于窗口的高度和宽度比率的变化(这是唯一的流程,因为看起来背景图像变形略有不同)。

最终结果移动并调整控件的大小非常好但是我们调整窗口的大小越多,差异就越明显,这可能是由于提到了转换差异。

<强>代码:

<强> ImageLayout.xaml:

    Title="Character sheet - Front" Height="768" Width="1366" SizeChanged="Window_SizeChanged">
<Window.Resources>
    <local:MarginConverter x:Key="MyConverter"/>
</Window.Resources>
<Window.Background>
    <ImageBrush ImageSource="Resources/base_front.png"/>
</Window.Background>
<Grid>
    <TextBox x:Name="TextBox" TextWrapping="Wrap" Text="TextBox">
        <TextBox.Margin>
            <MultiBinding Converter="{StaticResource MyConverter}" ConverterParameter="266,307,962,408">
                <Binding RelativeSource="{RelativeSource AncestorType={x:Type Window}}" Path="WindowProperties.CurrentWidthChange" />
                <Binding RelativeSource="{RelativeSource AncestorType={x:Type Window}}" Path="WindowProperties.CurrentHeightChange"/>
            </MultiBinding>
        </TextBox.Margin>
    </TextBox>
</Grid>

正如所述转换器在 ConverterParameter 中获取基本边距并且绑定到宽度/高度比率更改,(保留在附加类中) ,因为Window不是DependencyObject)。

<强> ImageLayout.xaml.cs:

public partial class ImageLayout : Window
{
    public WindowProperties WindowProperties { get; set; }

    public ImageLayout()
    {
        WindowProperties = new WindowProperties();

        InitializeComponent();
    }

    private void Window_SizeChanged(object sender, SizeChangedEventArgs e)
    {
        WindowProperties.CurrentHeightChange = e.NewSize.Height / 768;
        WindowProperties.CurrentWidthChange = e.NewSize.Width / 1366;
    }
}

这里我们只有 WindowProperties 的实例,它是实现 INotifyPropertyChanged 的类,另外我覆盖了一个在窗口的大小更改<上调用的事件/ strong>,以便更新宽度和高度变化的比率

<强> WindowProperties.cs:

public class WindowProperties : INotifyPropertyChanged
{
    public WindowProperties()
    {
        CurrentHeightChange = 1;
        CurrentWidthChange = 1;
    }

    private double _currentHeightChange;
    public double CurrentHeightChange
    {
        get
        {
            return _currentHeightChange;
        }
        set
        {
            _currentHeightChange = value;
            NotifyPropertyChanged("CurrentHeightChange");
        }
    }

    private double _currentWidthChange;
    public double CurrentWidthChange
    {
        get
        {
            return _currentWidthChange;
        }
        set
        {
            _currentWidthChange = value;
            NotifyPropertyChanged("CurrentWidthChange");
        }
    }

    public event PropertyChangedEventHandler PropertyChanged;

    protected virtual void NotifyPropertyChanged(string property)
    {
        if (PropertyChanged != null)
        {
            PropertyChanged(this, new PropertyChangedEventArgs(property));
        }
    }
}

实施转换器绑定目的所需的其他类 INotifyPropertyChanged

<强> MarginConverter.cs:

public class MarginConverter : IMultiValueConverter
{

    public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
    {
        string[] positions = parameter.ToString().Split(',');
        double leftPos = double.Parse(positions[0]);
        double topPos = double.Parse(positions[1]);
        double rightPos = double.Parse(positions[2]);
        double bottomPos = double.Parse(positions[3]);

        var actualMargin = new Thickness(leftPos, topPos, rightPos, bottomPos);

        return new Thickness(actualMargin.Left * (double)values[0],
                             actualMargin.Top * (double)values[1],
                             actualMargin.Right * (double)values[0],
                             actualMargin.Bottom * (double)values[1]);
    }

    public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
    {
        return null;
    }
}

转换器基本上从参数获取起始位置,然后将其乘以窗口大小变化的比率

<强>结果:

申请开始:

Application start

<强>调整大小:

After resize

大量调整大小,导致错误的转换:

Resizing flaw

<强>结论:

正如你所看到的那样它非常好用,如果调整大小选项有限,可以使用,为了使它更好,应该对比率计算做一些改进,但不幸的是我不知道精确转换< / strong>在调整窗口大小时完成背景图像。这种改进似乎有点矫枉过正,在我看来,通常最好只使用控件复制图像布局而不在背景中使用图像