wpf在代码隐藏中的Popup.IsOpen绑定不起作用(UserControl)

时间:2015-04-19 07:52:02

标签: c# wpf xaml user-controls

我是WPF和XAML的新手,无法在这里找到我做错的事。 我的UserControl控件很少,我需要从代码隐藏中控制Popup.IsOpen

public bool PopupVisible
{
    get 
    {
        //true
        if( txtSearch.IsKeyboardFocusWithin ) return true;               
        if( txtSearch.IsMouseOver ) return true;

        //false                
        if( txtSearch.IsKeyboardFocusWithin == false &&
            ( grid.IsMouseOver == false || popContainer.IsMouseOver == false || popContainer.IsMouseOver == false)
            )
        {
            return false;
        }

        return false;      
    }
}

我的XAML:

    <UserControl x:Class="Controls.KlasifikacijaBolestSearchBox.KlasifikacijaBolestSearchBox"
             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" 
             xmlns:controls="clr-namespace:Controls"
             xmlns:itemClass="clr-namespace:Controls.KlasifikacijaBolestSearchBox.ViewModels"
             x:Name="this"
             mc:Ignorable="d" 
             d:DesignHeight="300" d:DesignWidth="300" Loaded="this_Loaded">
    <Grid x:Name="grid" DataContext="{Binding Class}">
        <DockPanel LastChildFill="False">
            <controls:SearchTextBox x:Name="txtSearch" DockPanel.Dock="Top" TextChanged="txtSearch_TextChanged" OnSearch="txtSearch_OnSearch" Background="WhiteSmoke"></controls:SearchTextBox>
        </DockPanel>
        <Popup x:Name="popContainer"
                   Placement="Bottom"
                   PlacementTarget="{Binding ElementName=txtSearch}"               
                   AllowsTransparency="True"
                   StaysOpen="True"
                   IsOpen="{Binding PopupVisible, Mode=TwoWay}"
                   PopupAnimation="Fade"
                   MinWidth="500"
                   MinHeight="500"
                   Width="{Binding ElementName=txtSearch, Path=ActualWidth}">
            <DockPanel LastChildFill="True">
                <TextBlock DockPanel.Dock="Top" TextAlignment="Center" Text="Klasifikacija bolesti" FontWeight="Bold" Background="{DynamicResource WindowBackgroundBrush}" Foreground="White">
                </TextBlock>
                <TreeView
                            DockPanel.Dock="Top"
                            x:Name="tvKlasifikacijaBolest" 
                            ItemTemplate="{StaticResource tvKlasifikacijaBolestHDStyle}" 
                            ItemContainerStyle="{StaticResource tvKlasifikacijaBolestItemStyle}"
                            ScrollViewer.CanContentScroll="True"
                            ScrollViewer.VerticalScrollBarVisibility="Visible"
                            MouseDoubleClick="tvKlasifikacijaBolest_MouseDoubleClick">
                </TreeView>
            </DockPanel>
        </Popup>
    </Grid>
</UserControl> 

然后我想我需要实现INotifyPropertyChanged所以我将代码更改为:

private bool popupOpen;
public bool PopupOpen
{
    get { return popupOpen; }
    set
    {
        popupOpen = value;
        OnNotifyPropertyChanged("PopupOpen");
    }
}

private void txtSearch_TextChanged(string searchText, string searchType)
{
    PopupOpen = true;
}

当然改变了我的XAML部分:

<Popup x:Name="popContainer"
       IsOpen="{Binding PopupOpen, Mode=TwoWay}">
    <!-- ...  -->
</Popup>

我的弹出窗口永远不会被打开。 起初我使用了数据触发器并且它工作正常,直到我转向AllowTransparency="True"然后我的触发器有一些问题当我将鼠标移到我的控件上时poup的某些部分是透明的并且它关闭弹出窗口因此我改为代码隐藏但我不知道我做错了什么。

底线是 - 我需要在txtSearch.IsMouseOverIsKeyboardFocusedWithin或我的树视图IsMouseOver或弹出控件IsMouseOver = true中的任何子组件(边框,标签,文本块...)。 如果txtSearch具有焦点,那么如果IsMouseOver元素上的PopupTrueFalse,则弹出窗口需要保持打开状态。

2 个答案:

答案 0 :(得分:3)

你有两个问题。

注意:以下两段仅用于教育目的。

第一个。 PopupVisible从未通知它已更改。要通知目标,您需要对其进行更改,使其成为只读DependencyPrperty

private static readonly DependencyPropertyKey IsPopupOpenPropertyKey = DependencyProperty.RegisterReadOnly(
    "IsPopupOpen",
    typeof(bool),
    typeof(MainWindow),
    new FrameworkPropertyMetadata(false)
    );
private static readonly DependencyProperty IsPopupOpenProperty = IsPopupOpenPropertyKey.DependencyProperty;

public bool IsPopupOpen
{
    get { return (bool)GetValue(IsPopupOpenProperty); }
    private set { SetValue(IsPopupOpenPropertyKey, value); }
}

protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
{
    base.OnPropertyChanged(e);

    if (e.Property == UIElement.IsMouseOverProperty ||
        e.Property == UIElement.IsKeyboardFocusWithinProperty)
    {
        IsPopupOpen =
            txtSearch.IsMouseOver ||
            txtSearch.IsKeyboardFocusWithin;
    }
}

第二个。当您绑定到控件的属性时,您必须指定ElementNameRelativeSource。否则,Binding将在继承的数据上下文中查看该属性。

<UserControl x:Class="Controls.KlasifikacijaBolestSearchBox.KlasifikacijaBolestSearchBox"
             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
             xmlns:searchBox="Controls.KlasifikacijaBolestSearchBox">
    <!-- ... -->
    <Popup x:Name="popContainer"
           IsOpen="{Binding IsPopupOpen,
                            RelativeSource={RelativeSource AncestorType={x:Type searchBox:KlasifikacijaBolestSearchBox}},
                            Mode=OneWay}">

解决方案。要实现列出的行为,您应使用IMultiValueConverterMultiBinding

public sealed class OrConverter : IMultiValueConverter
{
    public object Convert(object[] values, System.Type targetType, object parameter, CultureInfo culture)
    {
        foreach (bool value in values)
        {
            if (value) { return true; }
        }

        return false;
    }

    public object[] ConvertBack(object value, System.Type[] targetTypes, object parameter, CultureInfo culture)
    {
        throw new NotSupportedException();
    }
}

XAML:

<UserControl x:Class="Controls.KlasifikacijaBolestSearchBox.KlasifikacijaBolestSearchBox"
         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" 
         xmlns:controls="clr-namespace:Controls"
         xmlns:converters="clr-namespace:Converters"
         xmlns:itemClass="clr-namespace:Controls.KlasifikacijaBolestSearchBox.ViewModels"
         x:Name="this"
         mc:Ignorable="d" 
         d:DesignHeight="300" d:DesignWidth="300" Loaded="this_Loaded">
<UserControl.Resources>
    <converters:OrConverter x:Key="Converter" />
</UserControl.Resources>
<Grid x:Name="grid" DataContext="{Binding Class}">
    <DockPanel LastChildFill="False">
        <TextBox x:Name="txtSearch"
                 Background="WhiteSmoke"
                 DockPanel.Dock="Top" />
    </DockPanel>
    <Popup x:Name="popContainer"
           Width="{Binding ElementName=txtSearch,
                           Path=ActualWidth}"
           MinWidth="500"
           MinHeight="500"
           AllowsTransparency="True"
           Placement="Bottom"
           PlacementTarget="{Binding ElementName=txtSearch}"
           PopupAnimation="Fade"
           StaysOpen="True">
        <Popup.IsOpen>
            <MultiBinding Converter="{StaticResource OrConverter}">
                <Binding ElementName="txtSearch" Path="IsMouseOver" Mode="OneWay" />
                <Binding ElementName="txtSearch" Path="IsKeyboardFocusWithin" Mode="OneWay" />
                <Binding ElementName="popContainer" Path="IsMouseOver" Mode="OneWay" />
            </MultiBinding>
        </Popup.IsOpen>

答案 1 :(得分:0)

尝试处理Popup的Opened和Closed事件。这是一个例子:Popup.Closed Event