두 개의 간단한 Model 클래스와 ViewModel이 있습니다.
public class GridItem
{
public string Name { get; set; }
public int CompanyID { get; set; }
}
public class CompanyItem
{
public int ID { get; set; }
public string Name { get; set; }
}
public class ViewModel
{
public ViewModel()
{
GridItems = new ObservableCollection<GridItem>() {
new GridItem() { Name = "Jim", CompanyID = 1 } };
CompanyItems = new ObservableCollection<CompanyItem>() {
new CompanyItem() { ID = 1, Name = "Company 1" },
new CompanyItem() { ID = 2, Name = "Company 2" } };
}
public ObservableCollection<GridItem> GridItems { get; set; }
public ObservableCollection<CompanyItem> CompanyItems { get; set; }
}
… 그리고 간단한 창 :
<Window x:Class="DataGridComboBoxColumnApp.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="MainWindow" Height="350" Width="525">
<Grid>
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding GridItems}" >
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" />
<DataGridComboBoxColumn ItemsSource="{Binding CompanyItems}"
DisplayMemberPath="Name"
SelectedValuePath="ID"
SelectedValueBinding="{Binding CompanyID}" />
</DataGrid.Columns>
</DataGrid>
</Grid>
</Window>
ViewModel은 DataContext
App.xaml.cs 의 MainWindow로 설정됩니다 .
public partial class App : Application
{
protected override void OnStartup(StartupEventArgs e)
{
base.OnStartup(e);
MainWindow window = new MainWindow();
ViewModel viewModel = new ViewModel();
window.DataContext = viewModel;
window.Show();
}
}
보시다시피 ItemsSource
DataGrid를 GridItems
ViewModel 컬렉션으로 설정 했습니다. 이 부분이 작동하면 이름이 “Jim”인 단일 그리드 선이 표시됩니다.
또한 ItemsSource
모든 행의 ComboBox를 CompanyItems
ViewModel 컬렉션 으로 설정하고 싶습니다 . 이 부분은 작동하지 않습니다. ComboBox가 비어 있고 디버거 출력 창에 오류 메시지가 표시됩니다.
System.Windows.Data 오류 : 2 : 대상 요소에 대한 관리 FrameworkElement 또는 FrameworkContentElement를 찾을 수 없습니다. BindingExpression : Path = CompanyItems; DataItem = null; 대상 요소는 ‘DataGridComboBoxColumn'(HashCode = 28633162)입니다. 대상 속성은 ‘ItemsSource'( ‘IEnumerable’유형)입니다.
WPF 는 그렇지 않은 CompanyItems
속성이 될 것으로 예상 GridItem
하고 바인딩이 실패하는 이유입니다.
나는 이미 a RelativeSource
와 AncestorType
같은 작업을 시도했습니다 .
<DataGridComboBoxColumn ItemsSource="{Binding CompanyItems,
RelativeSource={RelativeSource Mode=FindAncestor,
AncestorType={x:Type Window}}}"
DisplayMemberPath="Name"
SelectedValuePath="ID"
SelectedValueBinding="{Binding CompanyID}" />
하지만 디버거 출력에 또 다른 오류가 발생합니다.
System.Windows.Data 오류 : 4 : ‘RelativeSource FindAncestor, AncestorType =’System.Windows.Window ‘, AncestorLevel =’1 ”참조로 바인딩 할 소스를 찾을 수 없습니다. BindingExpression : Path = CompanyItems; DataItem = null; 대상 요소는 ‘DataGridComboBoxColumn'(HashCode = 1150788)입니다. 대상 속성은 ‘ItemsSource'( ‘IEnumerable’유형)입니다.
질문 : DataGridComboBoxColumn의 ItemsSource를 ViewModel의 CompanyItems 컬렉션에 바인딩하려면 어떻게해야합니까? 전혀 가능합니까?
미리 도와 주셔서 감사합니다!
답변
Pls, 아래 DataGridComboBoxColumn xaml이 작동하는지 확인하십시오.
<DataGridComboBoxColumn
SelectedValueBinding="{Binding CompanyID}"
DisplayMemberPath="Name"
SelectedValuePath="ID">
<DataGridComboBoxColumn.ElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding Path=DataContext.CompanyItems, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
</Style>
</DataGridComboBoxColumn.ElementStyle>
<DataGridComboBoxColumn.EditingElementStyle>
<Style TargetType="{x:Type ComboBox}">
<Setter Property="ItemsSource" Value="{Binding Path=DataContext.CompanyItems, RelativeSource={RelativeSource AncestorType={x:Type Window}}}" />
</Style>
</DataGridComboBoxColumn.EditingElementStyle>
</DataGridComboBoxColumn>
여기에서 직면하고있는 문제에 대한 다른 해결책을 찾을 수 있습니다 . WPF DataGrid와 함께 콤보 상자 사용
답변
그만큼 [정보 MSDN에 대한 문서 ItemsSource
의는DataGridComboBoxColumn
정적 자원, 콤보 상자 항목의 정적 코드 또는 인라인 컬렉션이 결합 될 수 있다고 말한다 ItemsSource
:
드롭 다운 목록을 채우려면 먼저 다음 옵션 중 하나를 사용하여 ComboBox의 ItemsSource 속성을 설정합니다.
- 정적 자원. 자세한 내용은 StaticResource 마크 업 확장을 참조하세요.
- x : Static 코드 엔티티. 자세한 내용은 x : Static Markup Extension을 참조하십시오.
- ComboBoxItem 유형의 인라인 컬렉션입니다.
올바르게 이해하면 DataContext의 속성에 바인딩 할 수 없습니다.
그리고 실제로 : 나는 할 때 정적의 뷰 모델에 속성을 …CompanyItems
public static ObservableCollection<CompanyItem> CompanyItems { get; set; }
… ViewModel이있는 네임 스페이스를 창에 추가합니다.
xmlns:vm="clr-namespace:DataGridComboBoxColumnApp"
… 바인딩을 …로 변경하십시오.
<DataGridComboBoxColumn
ItemsSource="{Binding Source={x:Static vm:ViewModel.CompanyItems}}"
DisplayMemberPath="Name"
SelectedValuePath="ID"
SelectedValueBinding="{Binding CompanyID}" />
… 그러면 작동합니다. 그러나 ItemsSource를 정적 속성으로 사용하는 것은 때때로 괜찮을 수 있지만 항상 원하는 것은 아닙니다.
답변
올바른 해결책은 다음과 같습니다.
<Window.Resources>
<CollectionViewSource x:Key="ItemsCVS" Source="{Binding MyItems}" />
</Window.Resources>
<!-- ... -->
<DataGrid ItemsSource="{Binding MyRecords}">
<DataGridComboBoxColumn Header="Column With Predefined Values"
ItemsSource="{Binding Source={StaticResource ItemsCVS}}"
SelectedValueBinding="{Binding MyItemId}"
SelectedValuePath="Id"
DisplayMemberPath="StatusCode" />
</DataGrid>
위의 레이아웃은 나에게 완벽하게 작동하며 다른 사람들에게도 작동합니다. 이 디자인 선택도 의미가 있지만 어디에도 잘 설명되어 있지는 않습니다. 그러나 미리 정의 된 값이있는 데이터 열이있는 경우 해당 값은 일반적으로 런타임 중에 변경되지 않습니다. 그래서 만들기CollectionViewSource
데이터를 만들고 초기화하는 것이 합리적입니다. 또한 조상을 찾고 데이터 컨텍스트에 바인딩하기 위해 더 긴 바인딩을 제거합니다 (항상 나에게 잘못되었다고 느꼈습니다).
이 바인딩으로 어려움을 겪은 다른 사람을 위해 여기를 남겨두고 더 나은 방법이 있는지 궁금해했습니다 (이 페이지가 여전히 검색 결과에 나타나기 때문에 여기에 왔습니다).
답변
나는이 질문이 1 년이 넘었다는 것을 알고 있지만 비슷한 문제를 처리하는 과정에서 우연히 발견했고 그것이 미래의 여행자 (또는 나 자신이 나중에 이것을 잊고 나를 발견 할 때 도움이 될 수있는 경우에 대비하여 다른 잠재적 인 해결책을 공유 할 것이라고 생각했습니다) 내 책상에서 가장 가까운 물체의 비명과 던지기 사이에 StackOverflow에서 펄럭입니다.
제 경우에는 DataGridComboBoxColumn 대신 DataGridTemplateColumn을 사용하여 원하는 효과를 얻을 수있었습니다. [주의 : 저는 .NET 4.0을 사용하고 있습니다. 제가 읽은 내용은 DataGrid가 많은 발전을 이루었다 고 믿게 만듭니다. 이전 버전을 사용하는 경우 YMMV]
<DataGridTemplateColumn Header="Identifier_TEMPLATED">
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox IsEditable="False"
Text="{Binding ComponentIdentifier,Mode=TwoWay,UpdateSourceTrigger=PropertyChanged}"
ItemsSource="{Binding Path=ApplicableIdentifiers, Mode=OneWay, UpdateSourceTrigger=PropertyChanged}" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding ComponentIdentifier}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
</DataGridTemplateColumn>
답변
RookieRick 사용하여, 권리 DataGridTemplateColumn
대신DataGridComboBoxColumn
사용하면 훨씬 더 간단한 XAML이 제공됩니다.
또한, 퍼팅 CompanyItem
로부터 직접 액세스 할 목록은 GridItem
당신이 없애 수 있습니다RelativeSource
.
IMHO, 이것은 당신에게 매우 깨끗한 솔루션을 제공합니다.
XAML :
<DataGrid AutoGenerateColumns="False" ItemsSource="{Binding GridItems}" >
<DataGrid.Resources>
<DataTemplate x:Key="CompanyDisplayTemplate" DataType="vm:GridItem">
<TextBlock Text="{Binding Company}" />
</DataTemplate>
<DataTemplate x:Key="CompanyEditingTemplate" DataType="vm:GridItem">
<ComboBox SelectedItem="{Binding Company}" ItemsSource="{Binding CompanyList}" />
</DataTemplate>
</DataGrid.Resources>
<DataGrid.Columns>
<DataGridTextColumn Binding="{Binding Name}" />
<DataGridTemplateColumn CellTemplate="{StaticResource CompanyDisplayTemplate}"
CellEditingTemplate="{StaticResource CompanyEditingTemplate}" />
</DataGrid.Columns>
</DataGrid>
모델보기 :
public class GridItem
{
public string Name { get; set; }
public CompanyItem Company { get; set; }
public IEnumerable<CompanyItem> CompanyList { get; set; }
}
public class CompanyItem
{
public int ID { get; set; }
public string Name { get; set; }
public override string ToString() { return Name; }
}
public class ViewModel
{
readonly ObservableCollection<CompanyItem> companies;
public ViewModel()
{
companies = new ObservableCollection<CompanyItem>{
new CompanyItem { ID = 1, Name = "Company 1" },
new CompanyItem { ID = 2, Name = "Company 2" }
};
GridItems = new ObservableCollection<GridItem> {
new GridItem { Name = "Jim", Company = companies[0], CompanyList = companies}
};
}
public ObservableCollection<GridItem> GridItems { get; set; }
}
답변
ComboBox가 GridItem[x].CompanyItems
존재하지 않는 에 바인딩하려고 합니다.
RelativeBinding이 닫혀 있지만 DataContext.CompanyItems
Window.CompanyItems가 존재하지 않기 때문에 바인딩해야 합니다.
답변
내가 사용하는 인색 한 방법은 textblock과 combobox를 동일한 속성에 바인딩 하고이 속성은 notifyPropertyChanged를 지원해야합니다.
이 경우 datagrid는 datagrid.itemsource에서 사용한 객체에서 데이터 그리드가 검색되기 때문에 바인딩에서 datagrid 수준으로 올라가는 usercontrol 인 parent view datacontext에 바인딩하는 relativeresource를 사용했습니다.
<DataGridTemplateColumn Header="your_columnName">
<DataGridTemplateColumn.CellTemplate>
<DataTemplate>
<TextBlock Text="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Path=DataContext.SelectedUnit.Name, Mode=TwoWay}" />
</DataTemplate>
</DataGridTemplateColumn.CellTemplate>
<DataGridTemplateColumn.CellEditingTemplate>
<DataTemplate>
<ComboBox DisplayMemberPath="Name"
IsEditable="True"
ItemsSource="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Path=DataContext.UnitLookupCollection}"
SelectedItem="{Binding RelativeSource={RelativeSource AncestorType={x:Type UserControl}}, Path=DataContext.SelectedUnit, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedValue="{Binding UnitId, Mode=TwoWay, UpdateSourceTrigger=PropertyChanged}"
SelectedValuePath="Id" />
</DataTemplate>
</DataGridTemplateColumn.CellEditingTemplate>
</DataGridTemplateColumn>