场景:一个信息窗体,用Grid分成两列,左边的是信息列表自定义控件,右边的是信息内容自定义控件(高度未占满整列),当点击信息列表中的某一条信息时,信息内容控件的位置要与列表中所选中的那条信息对齐。
以下为DEMO代码:
MainWindows.xaml:
<Window x:Class="NotifyProperty.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:Msg="clr-namespace:NotifyProperty"
x:Name="mainWin"
Title="MainWindow" Height="600" Width="800">
<Grid x:Name="grid">
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
<!--信息列表-->
<Msg:MessageList x:Name="MsgList" Grid.Column="0"/>
<!--信息内容-->
<Msg:MsgInfo x:Name="msgInfo" Grid.Column="1" Width="300" Height="200" Margin="20,20,0,0" VerticalAlignment="Top" HorizontalAlignment="Left"/>
<TextBlock Text="{Binding ElementName=mainWin, Path=MarginTop}" Margin="20,20,0,0" Grid.ColumnSpan="2" Grid.Column="1" />
</Grid>
</Window>
MainWindows.xaml.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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;
using System.ComponentModel;
namespace NotifyProperty
{
/// <summary>
/// MainWindow.xaml 的交互逻辑
/// </summary>
public partial class MainWindow : Window
{
public Double MarginTop
{
get { return (Double)GetValue(MarginTopProperty); }
set { SetValue(MarginTopProperty, value); }
}
// Using a DependencyProperty as the backing store for MarginTop. This enables animation, styling, binding, etc...
public static readonly DependencyProperty MarginTopProperty =
DependencyProperty.Register("MarginTop", typeof(Double), typeof(MainWindow));
DependencyPropertyDescriptor dpd = DependencyPropertyDescriptor.FromProperty(MarginTopProperty, typeof(MainWindow));
public MainWindow()
{
InitializeComponent();
//属性绑定
Binding binding = new Binding();
binding.Source = MsgList;
binding.Path = new PropertyPath("MarginTop");
BindingOperations.SetBinding(this, MarginTopProperty, binding);
//附加属性监听
dpd.AddValueChanged(this, OnMyDependencyPropertyChanged);
}
/// <summary>
/// 附加属性监听事件
/// 计算MsgInfo对象的Margin-Top
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void OnMyDependencyPropertyChanged(object sender, EventArgs e)
{
double mLeft = 20;
double mTop = 0;
double parentHeight = grid.ActualHeight-20;
if (MarginTop + msgInfo.Height > parentHeight)
{
mTop = parentHeight - msgInfo.Height;
}
else
{
mTop = MarginTop;
if (mTop < 20)
{
mTop = 20;
}
}
msgInfo.Margin = new Thickness(mLeft, mTop, 0, 0);
}
}
}
MessageList.xaml:
<UserControl x:Class="NotifyProperty.MessageList"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="300" d:DesignWidth="300">
<Grid x:Name="grid">
<ListBox x:Name="lvStudent" ItemsSource="{Binding}" Width="{Binding ElementName=grid, Path=ActualWidth}" MouseLeftButtonUp="lvStudent_MouseLeftButtonUp" >
<ListBox.ItemTemplate>
<DataTemplate>
<Border BorderBrush="Blue" BorderThickness="1" Margin="5" Width="300" Height="80">
<TextBlock Text="{Binding Age}" FontSize="26"/>
</Border>
</DataTemplate>
</ListBox.ItemTemplate>
</ListBox>
</Grid>
</UserControl>
MessageList.xaml.cs
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
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;
using System.ComponentModel;
using System.Diagnostics;
namespace NotifyProperty
{
/// <summary>
/// MessageList.xaml 的交互逻辑
/// </summary>
public partial class MessageList : UserControl, INotifyPropertyChanged
{
private double marginTop;
public double MarginTop
{
get { return marginTop; }
set
{
marginTop = value;
RaisePropertyChanged("MarginTop");
}
}
public MessageList()
{
InitializeComponent();
List<Student> stuList = new List<Student>();
for (int i = 0; i < 10; i++)
{
Student stu = new Student();
stu.Age = i;
stuList.Add(stu);
}
this.lvStudent.ItemsSource = stuList;
}
/// <summary>
/// 列表点击事件
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void lvStudent_MouseLeftButtonUp(object sender, MouseButtonEventArgs e)
{
ListBoxItem lbi = null;
if (lvStudent.Items.Count > 0 && lvStudent.SelectedIndex != -1)
{
lbi = lvStudent.ItemContainerGenerator.ContainerFromIndex(lvStudent.SelectedIndex) as ListBoxItem;
}
Point point = e.MouseDevice.GetPosition(this);
if (lbi != null)
{
MarginTop = point.Y - e.MouseDevice.GetPosition(lbi).Y;// +lbi.ActualHeight / 2;
}
else
{
MarginTop = point.Y;
}
}
#region Notify Method
public event PropertyChangedEventHandler PropertyChanged;
protected void RaisePropertyChanged(string propertyName)
{
this.VerifyPropertyName(propertyName);
PropertyChangedEventHandler handler = this.PropertyChanged;
if (handler != null)
{
var e = new PropertyChangedEventArgs(propertyName);
handler(this, e);
}
}
#region 属性名验证
protected virtual bool ThrowOnInvalidPropertyName { get; private set; }
[Conditional("DEBUG")]
[DebuggerStepThrough]
public void VerifyPropertyName(string propertyName)
{
// If you raise PropertyChanged and do not specify a property name,
// all properties on the object are considered to be changed by the binding system.
if (String.IsNullOrEmpty(propertyName))
return;
// Verify that the property name matches a real,
// public, instance property on this object.
if (TypeDescriptor.GetProperties(this)[propertyName] == null)
{
string msg = "Invalid property name: " + propertyName;
if (this.ThrowOnInvalidPropertyName)
throw new ArgumentException(msg);
else
Debug.Fail(msg);
}
}
#endregion
#endregion
}
public class Student
{
public int Age { get; set; }
}
}
MsgInfo.xaml:
<UserControl x:Class="NotifyProperty.MsgInfo"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
mc:Ignorable="d"
d:DesignHeight="600" d:DesignWidth="800">
<Border BorderBrush="Red" BorderThickness="2"/>
</UserControl>
MsgInfo.xaml.cs: ~Nothing~~
以上为简单实现的代码,接触WPF不久,不足的地方,还望高手们指正~~