2010-01-18 4 views
8

WPF를 사용하여 ListBox 컨트롤에 DataTemplate 컨트롤이 있습니다. 관련 XAML 코드는 다음과 같습니다 :WPF (데이터 템플릿)가있는 ListBox에서 TextBlock을 인라인 편집

<ListBox Name="_todoList" Grid.Row="1" BorderThickness="2" 
    Drop="todoList_Drop" AllowDrop="True" 
    HorizontalContentAlignment="Stretch" 
    ScrollViewer.HorizontalScrollBarVisibility="Disabled"     
    AlternationCount="2"> 
    <ListBox.ItemTemplate> 
     <DataTemplate> 
      <Grid Margin="4"> 
       <Grid.ColumnDefinitions> 
        <ColumnDefinition Width="Auto" /> 
        <ColumnDefinition Width="*" /> 
       </Grid.ColumnDefinitions> 
       <CheckBox Grid.Column="0" Checked="CheckBox_Check" /> 
       <TextBlock Name="descriptionBlock" 
          Grid.Column="1" 
          Text="{Binding Description}" 
          Cursor="Hand" FontSize="14" 
          ToolTip="{Binding Description}" 
          MouseDown="TextBlock_MouseDown" />      
      </Grid> 
     </DataTemplate> 
    </ListBox.ItemTemplate> 
</ListBox> 

는 내가 뭘하려고하는 것은 TextBox로 바뀝니다하는 클릭 (더블)에 TextBlock 응답을 할 수 있습니다. 그런 다음 설명을 편집하고 돌아가거나 포커스를 변경하여 변경 사항을 적용 할 수 있습니다.

나는 TextBlock의 같은 위치에 TextBox 요소를 추가하고 가시성 Collapsed 만드는 시도,하지만 사용자가 TextBlock를 클릭했을 때 올바른 TextBox로 이동하는 방법을 모르겠어요. 즉, 사용자가 특정 TextBlock을 클릭했음을 알고 있습니다. 현재 입니다.TextBox을 표시합니까?

어떤 도움을 크게 감상 할 수

,

-Ko9

+0

팁으로 'pre' 태그를 사용하고 꺾쇠 괄호를 명시 적으로 이스케이프 처리하는 대신 XAML을 편집기에 직접 붙여넣고 101010 버튼을 사용하여 코드로 포맷 할 수 있습니다. – itowlson

답변

14

이러한 상황에서 내가 한 것은 XAML 계층 구조를 사용하여 표시/숨길 요소를 결정하는 것입니다. 코드와

<Grid> 
    <TextBlock MouseDown="txtblk_MouseDown" /> 
    <TextBox LostFocus="txtbox_LostFocus" Visibility="Collapsed" /> 
</Grid> 

:의 라인을 따라 뭔가

protected void txtblk_MouseDown(object sender, MouseButtonEventArgs e) 
{ 
    TextBox txt = (TextBox)((Grid)((TextBlock)sender).Parent).Children[1]; 
    txt.Visibility = Visibility.Visible; 
    ((TextBlock)sender).Visibility = Visibility.Collapsed; 
} 

protected void txtbox_LostFocus(object sender, RoutedEventArgs e) 
{ 
    TextBlock tb = (TextBlock)((Grid)((TextBox)sender).Parent).Children[0]; 
    tb.Text = ((TextBox)sender).Text; 
    tb.Visibility = Visibility.Visible; 
    ((TextBox)sender).Visibility = Visibility.Collapsed; 
} 

난 항상 내가 추가 오류가 처리 추가 할 수 UserControl로 재사용 할거야 그 같은 물건을 돌려, Grid에는 두 개의 항목 만 포함되며 그 순서는 변경되지 않습니다.

편집 : 또한, UserControl이이 점을 돌리면 각 하나의 이름을 직접 ((TextBox)myGrid.Children[1]).Text 캐스팅을 통해 현재 값 낚시를하지 않고 텍스트를 참조 할 수 있도록, 각 인스턴스에 대한 Text 속성을 만들 수 있습니다.이렇게하면 코드를 훨씬 더 효율적이고 깨끗하게 만들 수 있습니다. UserControl로 만들면 TextBlockTextBox 요소의 이름을 지정할 수 있으므로 캐스팅이 필요하지 않습니다.

+0

이것이 이상하게 들릴 수 있습니다. 답변을 편집 할 수 있습니까? 내가 성급하게 클릭 한 다음 내 투표를 삭제했습니다. 왜냐하면 이것이 내가 나중에 무엇인지 확실하지 않았기 때문입니다. 나는 그것이 필요한 것이기 때문에 다시 투표를 올리려고했는데 Stack Overflow는 그것이 편집되지 않았다면이 게시물에 투표 할 수 없다고 말합니다. 그러므로 요청. 건배, 매우 유용한 게시물로 밝혀졌습니다. –

4

기본적으로 텍스트 상자를 TextBlock의로 렌더링하지만 표시하는 ClickEditableTextBlock 컨트롤을 생성하는 것이 작업을 수행 할 수있는 이상적인 방법 때 사용자가 클릭 그것. 주어진 ClickEditableTextBlock에는 TextBlock과 TextBox가 하나만 있기 때문에 일치하는 문제가 없습니다. 그런 다음 DataTemplate에서 별도의 TextBlocks 및 TextBoxes 대신 ClickEditableTextBlock을 사용합니다.

이 기능은 컨트롤의 기능을 캡슐화하여 편집 동작으로 기본 창 코드 숨김을 오염시키지 않고 다른 템플릿에서 쉽게 다시 사용할 수있는 이점이 있습니다.


이 너무 많은 노력 같은 소리가 나는 경우에, 당신이 텍스트 상자에 각 TextBlock을 연결하는 태그 또는 연결된 속성을 사용할 수 있습니다 태그에 {Binding ElementName=tb}의 사용이 참조하는

<DataTemplate> 
    <StackPanel> 
    <TextBlock Text="whatever" 
       MouseDown="TextBlock_MouseDown" 
       Tag="{Binding ElementName=tb}" /> 
    <TextBox Name="tb" /> 
    </StackPanel> 
</DataTemplate> 

주 텍스트 상자는 tb입니다.

와의

코드 숨김

private void TextBlock_MouseDown(object sender, MouseButtonEventArgs e) 
{ 
    FrameworkElement textBlock = (FrameworkElement)sender; 
    TextBox editBox = (TextBox)(textBlock.Tag); 
    editBox.Text = "Wow!"; // or set visible or whatever 
} 

(, 당신은 텍스트 상자 바인딩을 수행하기 위해 사용자 지정 연결된 속성을 정의 할 수 불쾌한 태그 속성의 사용을 방지하기 위해,하지만 간결 내가 보여주는 아니에요 그.)

11

Nathan Wheeler의 코드 스 니펫을 참조하면 다음 코드는 어제 코딩 한 완전한 UserControl 소스입니다. 특히 바인딩 문제가 해결되었습니다. Nathan의 코드는 쉽게 따라 할 수 있지만 데이터 바인딩 된 텍스트로 작업하려면 약간의 도움이 필요합니다.

ClickToEditTextboxControl.xaml.cs

public partial class ClickToEditTextboxControl : UserControl 
{ 
    public ClickToEditTextboxControl() 
    { 
     InitializeComponent(); 
    } 

    public string Text 
    { 
     get { return (string)GetValue(TextProperty); } 
     set { SetValue(TextProperty, value); } 
    } 

    // Using a DependencyProperty as the backing store for Text. This enables animation, styling, binding, etc... 
    public static readonly DependencyProperty TextProperty = 
     DependencyProperty.Register("Text", typeof(string), typeof(ClickToEditTextboxControl), new UIPropertyMetadata()); 

    private void textBoxName_LostFocus(object sender, RoutedEventArgs e) 
    { 
     var txtBlock = (TextBlock)((Grid)((TextBox)sender).Parent).Children[0]; 

     txtBlock.Visibility = Visibility.Visible; 
     ((TextBox)sender).Visibility = Visibility.Collapsed; 
    } 

    private void textBlockName_MouseDown(object sender, MouseButtonEventArgs e) 
    { 
     var grid = ((Grid) ((TextBlock) sender).Parent); 
     var tbx = (TextBox)grid.Children[1]; 
     ((TextBlock)sender).Visibility = Visibility.Collapsed; 
     tbx.Visibility = Visibility.Visible; 

     this.Dispatcher.BeginInvoke((Action)(() => Keyboard.Focus(tbx)), DispatcherPriority.Render); 
    } 

    private void TextBoxKeyDown(object sender, KeyEventArgs e) 
    { 
     if (e == null) 
      return; 

     if (e.Key == Key.Return) 
     { 
      TextBoxLostFocus(sender, null); 
     } 
    } 
} 

ClickToEditTextboxControl.xaml

<UserControl x:Class="Template.ClickToEditTextboxControl" 
     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" 
     Name="root" 
     d:DesignHeight="30" d:DesignWidth="100"> 
<Grid> 
    <TextBlock Name="textBlockName" Text="{Binding ElementName=root, Path=Text}" VerticalAlignment="Center" MouseDown="textBlockName_MouseDown" /> 
    <TextBox Name="textBoxName" Text="{Binding ElementName=root, Path=Text, UpdateSourceTrigger=PropertyChanged}" Visibility="Collapsed" LostFocus="textBoxName_LostFocus" KeyDown ="TextBoxKeyDown"/> 
</Grid> 
</UserControl> 

그리고 마지막으로, 당신은 아래와 같이 XAML에서이 컨트롤을 사용할 수 있습니다

<Template1:ClickToEditTextboxControl Text="{Binding Path=Name, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}" MinWidth="40" Height="23" /> 

참고 모드 = TwoWay, UpdateSourceTrigger = PropertyChanged이 설정됩니다. 모든 유형의 바인드 값을 변경할 수 있습니다.

관련 문제