Plateforme Level Extreme
Abonnement
Profil corporatif
Produits & Services
Support
Légal
English
WPF Popup - Form Moved
Message
De
27/02/2008 13:57:21
 
 
À
27/02/2008 13:22:47
Information générale
Forum:
ASP.NET
Catégorie:
Code, syntaxe and commandes
Divers
Thread ID:
01295934
Message ID:
01297029
Vues:
29
Ooof! More than I bargained for <g>
I was intially intrigued by 'The Popup does not stay with the textbox if the window is moved' and wonder why that would be the case.
I think I'm well behind you on the learning curve on this one and I'm also tied up for the next couple of days but I do want to play with it when I get time....
Regards,
Viv



>>>Everything is working good, except I need to close the popup if the user moves the window. The Popup does not stay with the textbox if the window is moved, and closing it is easier than making it follow.
>>>
>>>The question is... How do I drill down from my custom control to access an event that will tell me that the form has moved?
>>
>>Could you post the XAML for this?
>>Best,
>>Viv
>
>Ok... It's a custom control, so it uses the Generic.xaml in the Themes folder.
>
>
><ResourceDictionary
>  xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
>  xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
>  xmlns:local="clr-namespace:CDS3.ControlsWPF">
>  <Style TargetType="{x:Type local:cdsPopUpListBox}">
>    <Setter Property="Margin" Value="1"/>
>    <Setter Property="Template">
>      <!-- ScrollViewer must be set -->
>      <Setter.Value>
>        <ControlTemplate TargetType="{x:Type local:cdsPopUpListBox}">
>          <Border
>            Name="Border"
>            Background="WhiteSmoke"
>            BorderBrush="Black"
>            BorderThickness="1">
>            <ScrollViewer
>              Margin="0"
>              Focusable="false" VerticalScrollBarVisibility="Auto">
>              <StackPanel Margin="2" IsItemsHost="True" />
>            </ScrollViewer>
>          </Border>
>        </ControlTemplate>
>      </Setter.Value>
>    </Setter>
>  </Style>
>  <Style TargetType="{x:Type local:cdsAutoComplete}">
>    <Setter Property="Template">
>    <!--Create a TextBox that looks "flat".
        The control template for a TextBox or RichTextBox must
        include an element tagged as the content host.  An element is
        tagged as the content host element when it has the special name
        PART_ContentHost.  The content host element must be a ScrollViewer,
        or an element that derives from Decorator.
        -->
>    <Setter.Value>
>      <ControlTemplate TargetType="{x:Type local:cdsAutoComplete}">
>        <Border Background="{TemplateBinding Background}"
>                BorderBrush="{TemplateBinding BorderBrush}"
>                BorderThickness="{TemplateBinding BorderThickness}"
>                Padding="2,4,2,2">
>          <Decorator x:Name="PART_ContentHost"/>
>        </Border>
>       </ControlTemplate>
>      </Setter.Value>
>    </Setter>
>  </Style>
></ResourceDictionary>
>
>
>It took me forever to figure out that I had to have ScrollViewer in there I only managed to figure it out by trial and error. A number of the attributes in there should probably be set back to TemplateBinding.
>
>Then there is the code behind for the popup.
>
>
>using System;
>using System.Collections.Generic;
>using System.Linq;
>using System.Text;
>using System.Windows;
>using System.Windows.Controls;
>using System.Windows.Controls.Primitives;
>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 CDS3.ControlsWPF
>  {
>  /// <summary>
>  /// Popup List box.
>  /// </summary>
>  public partial class cdsPopUpListBox : System.Windows.Controls.ListBox
>    {
>
>    //http://blogs.msdn.com/wpfsdk/archive/2007/04/27/popup-your-control.aspx
>
>    Popup _parentPopup;
>
>    public cdsPopUpListBox() : base()
>      {
>      LostKeyboardFocus += new KeyboardFocusChangedEventHandler(cdsPopUpListBox_LostKeyboardFocus);
>      }
>
>    static cdsPopUpListBox()
>      {
>      //This OverrideMetadata call tells the system that this element
>      //wants to provide a style that is different than its base class.
>      //This style is defined in themes\generic.xaml
>      DefaultStyleKeyProperty.OverrideMetadata(typeof(cdsPopUpListBox),
>                new FrameworkPropertyMetadata(typeof(cdsPopUpListBox)));
>      }
>
>    void cdsPopUpListBox_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
>      {
>      if (e.NewFocus == null)
>        IsOpen = false;
>      else if (!e.NewFocus.ToString().StartsWith("System.Windows.Controls.ListBoxItem:"))
>        IsOpen = false;
>      }
>
>    //Placement
>    public static readonly DependencyProperty PlacementProperty =
>                Popup.PlacementProperty.AddOwner(typeof(cdsPopUpListBox));
>
>    public PlacementMode Placement
>      {
>      get { return (PlacementMode)GetValue(PlacementProperty); }
>      set { SetValue(PlacementProperty, value); }
>      }
>
>    //PlacementTarget
>    public static readonly DependencyProperty PlacementTargetProperty =
>       Popup.PlacementTargetProperty.AddOwner(typeof(cdsPopUpListBox));
>
>    public UIElement PlacementTarget
>      {
>      get { return (UIElement)GetValue(PlacementTargetProperty); }
>      set { SetValue(PlacementTargetProperty, value); }
>      }
>
>    //PlacementRectangle
>    public static readonly DependencyProperty PlacementRectangleProperty =
>                Popup.PlacementRectangleProperty.AddOwner(typeof(cdsPopUpListBox));
>
>    public Rect PlacementRectangle
>      {
>      get { return (Rect)GetValue(PlacementRectangleProperty); }
>      set { SetValue(PlacementRectangleProperty, value); }
>      }
>
>    //HorizontalOffset
>    public static readonly DependencyProperty HorizontalOffsetProperty =
>        Popup.HorizontalOffsetProperty.AddOwner(typeof(cdsPopUpListBox));
>
>    public double HorizontalOffset
>      {
>      get { return (double)GetValue(HorizontalOffsetProperty); }
>      set { SetValue(HorizontalOffsetProperty, value); }
>      }
>
>    //VerticalOffset
>    public static readonly DependencyProperty VerticalOffsetProperty =
>            Popup.VerticalOffsetProperty.AddOwner(typeof(cdsPopUpListBox));
>
>    public double VerticalOffset
>      {
>      get { return (double)GetValue(VerticalOffsetProperty); }
>      set { SetValue(VerticalOffsetProperty, value); }
>      }
>
>    public static readonly DependencyProperty IsOpenProperty =
>            Popup.IsOpenProperty.AddOwner(
>                    typeof(cdsPopUpListBox),
>                    new FrameworkPropertyMetadata(
>                            false,
>                            FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
>                            new PropertyChangedCallback(OnIsOpenChanged)));
>
>    public bool IsOpen
>      {
>      get { return (bool)GetValue(IsOpenProperty); }
>      set { SetValue(IsOpenProperty, value); }
>      }
>
>    private static void OnIsOpenChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
>      {
>      cdsPopUpListBox ctrl = (cdsPopUpListBox)d;
>      if ((bool)e.NewValue)
>        {
>        if (ctrl._parentPopup == null)
>          {
>          ctrl.HookupParentPopup();
>          }
>        }
>      }
>
>    private void HookupParentPopup()
>      {
>      _parentPopup = new Popup();
>      _parentPopup.AllowsTransparency = true;
>      Popup.CreateRootPopup(_parentPopup, this);
>      }
>    }
>  }
>
>
>The source for most of that code came from the link next to the class definition. I just changed it from a textbox to a listbox.
>
>Now the text box:
>
>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.Windows.Markup;
>
>namespace CDS3.ControlsWPF
>  {
>  /// <summary>
>  /// Auto complete TextBox
>  ///
>  /// current project: xmlns:MyNamespace="clr-namespace:CDS3.ControlsWPF"
>  /// different project: xmlns:MyNamespace="clr-namespace:CDS3.ControlsWPF;assembly=CDS3.ControlsWPF"
>  /// project reference :
>  ///
>  ///     Right click on the target project in the Solution Explorer and
>  ///     "Add Reference"->"Projects"->[Browse to and select this project]
>  ///
>  /// use your control in the XAML file: <MyNamespace:cdsAutoComplete/>
>  /// </summary>
>  public class cdsAutoComplete : TextBox
>    {
>
>    public  IEnumerable<cdsAutoCompleteItems> AutoCompleteList;
>    public  bool Constrain2List { get; set; }
>    private int _ID;
>    public int ID {
>      get { return _ID; }
>    set
>      {
>      _ID = value;
>      string nm = (from items in AutoCompleteList
>                   where items.ID == value
>                   select items.Name).First();
>      this.Text = nm;
>      }
>    }
>
>    private cdsPopUpListBox popup;
>
>    #region Constructors
>
>    public cdsAutoComplete() : base()
>      {
>      popup = new cdsPopUpListBox();
>      popup.PlacementTarget = this;
>      LostKeyboardFocus += new KeyboardFocusChangedEventHandler(cdsAutoComplete_LostKeyboardFocus);
>      KeyUp += new KeyEventHandler(cdsAutoComplete_KeyUp);
>      popup.KeyUp += new KeyEventHandler(popup_KeyUp);
>      Constrain2List = false;
>      }
>
>    static cdsAutoComplete()
>      {
>      DefaultStyleKeyProperty.OverrideMetadata(typeof(cdsAutoComplete), new FrameworkPropertyMetadata(typeof(cdsAutoComplete)));
>      }
>
>    #endregion
>
>    #region Events
>
>    void cdsAutoComplete_KeyUp(object sender, KeyEventArgs e)
>      {
>      //var xConverter = new KeyConverter();
>      //char xChar = xConverter.ConvertToString(e.Key)[0];
>      if (e.Key == System.Windows.Input.Key.Enter)
>        TogglePopup(false);
>      else if (e.Key == System.Windows.Input.Key.Down)
>        {
>        object item = popup.Items[0];
>        popup.SelectedItem = item;
>        ListBoxItem lbi = (ListBoxItem)popup.ItemContainerGenerator.ContainerFromItem(item);
>        lbi.Focus();
>        }
>      else
>        {
>        string entered = ((TextBox)sender).Text;
>        popup.Items.Clear();
>        var selected = (from items in AutoCompleteList
>                        where items.Name.ToUpper().StartsWith(entered.ToUpper())
>                        select items).Take(5);
>        if (selected.Count()>0)
>          {
>          int selectstart = this.SelectionStart;
>          this.Text       = selected.First().Name;
>          this.SelectionStart = selectstart;
>          this.SelectionLength = this.Text.Length - selectstart;
>          //System.Windows.Forms.MessageBox.Show(this.SelectionStart.ToString());
>          this.Text = selected.First().Name;
>          foreach (var sel in selected)
>            {
>            popup.Items.Add(sel.Name);
>            }
>          TogglePopup(true);
>          }
>        else
>          TogglePopup(false);
>        }
>      }
>
>    void cdsAutoComplete_LostKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
>      {
>      if (e.NewFocus == null)
>        popup.IsOpen = false;
>      else if (!e.NewFocus.ToString().StartsWith("System.Windows.Controls.ListBoxItem:"))
>        popup.IsOpen = false;
>      }
>
>    void popup_KeyUp(object sender, KeyEventArgs e)
>      {
>      if (e.Key == System.Windows.Input.Key.Enter)
>        {
>        this.Text = popup.SelectedItem.ToString();
>        TogglePopup(false);
>        }
>      }
>
>    #endregion
>
>    void TogglePopup(bool showPopup)
>      {
>      popup.MinWidth = this.ActualWidth;
>      popup.IsOpen = showPopup;
>      }
>
>    }
>
>  public class cdsAutoCompleteItems
>    {
>    public int ID { get; set; }
>    public string Name { get; set; }
>
>    public cdsAutoCompleteItems(int id,string name)
>      {
>      ID = id;
>      Name = name;
>      }
>    }
>
>  }
>
>
>Now that code is still unfinished, and is real rough. I have more events to handle and more keyboard handling still to write, features to add, etc etc. Parts of it have not even been tested yet.
>
>I fill it using Linq. (But any IEnumerable would do)
>
>
>      cdsPayablesDCDataContext dc = new cdsPayablesDCDataContext();
>      AutoCompBox.AutoCompleteList = from acts in dc.cdsEntities
>                                  where acts.RecordType == 'A'
>                                  select new cdsAutoCompleteItems(acts.ID, acts.Name.Trim());
>
>
>And to use it:
>
>
>    <!-- in the host controls header  xmlns:local="clr-namespace:CDS3.ControlsWPF"  -->
>    <Grid.Resources>
>      <Style TargetType="local:cdsAutoComplete">
>        <Setter Property="BorderThickness" Value="1" />
>        <Setter Property="Background" Value="White"/>
>        <Setter Property="Width" Value="250"/>
>      </Style>
>    </Grid.Resources>
>    <local:cdsAutoComplete
>      Height="23"
>      HorizontalAlignment="Left"
>      Margin="43,15,0,0"
>      x:Name="AutoComp"
>      VerticalAlignment="Top"
>      Constrain2List ="True"
>      Width="140"
>      BorderBrush="#FFA5ACB2" />
>
>
>As I mentioned above, it's still pretty rough, and missing a number of event handlers.
>
>But it does work.
Précédent
Suivant
Répondre
Fil
Voir

Click here to load this message in the networking platform