나는이 TextBox
과를Button
내보기에.
이제 버튼 클릭시 조건을 확인하고 조건이 거짓으로 판명되면 사용자에게 메시지를 표시 한 다음 커서를 TextBox
컨트롤 로 설정해야합니다 .
if (companyref == null)
{
var cs = new Lipper.Nelson.AdminClient.Main.Views.ContactPanels.CompanyAssociation();
MessageBox.Show("Company does not exist.", "Error", MessageBoxButton.OK,
MessageBoxImage.Exclamation);
cs.txtCompanyID.Focusable = true;
System.Windows.Input.Keyboard.Focus(cs.txtCompanyID);
}
위의 코드는 ViewModel에 있습니다.
그만큼 CompanyAssociation
뷰 이름입니다.
그러나 커서가 TextBox
.
xaml은 다음과 같습니다.
<igEditors:XamTextEditor Name="txtCompanyID"
KeyDown="xamTextEditorAllowOnlyNumeric_KeyDown"
ValueChanged="txtCompanyID_ValueChanged"
Text="{Binding Company.CompanyId,
Mode=TwoWay,
UpdateSourceTrigger=PropertyChanged}"
Width="{Binding ActualWidth, ElementName=border}"
Grid.Column="1" Grid.Row="0"
VerticalAlignment="Top"
HorizontalAlignment="Stretch"
Margin="0,5,0,0"
IsEnabled="{Binding Path=IsEditable}"/>
<Button Template="{StaticResource buttonTemp1}"
Command="{Binding ContactCommand}"
CommandParameter="searchCompany"
Content="Search"
Width="80"
Grid.Row="0" Grid.Column="2"
VerticalAlignment="Top"
Margin="0"
HorizontalAlignment="Left"
IsEnabled="{Binding Path=IsEditable}"/>
답변
세 부분으로 귀하의 질문에 대답하겠습니다.
-
귀하의 예에서 “cs.txtCompanyID”가 무엇인지 궁금합니다. TextBox 컨트롤입니까? 그렇다면, 당신은 잘못된 길을 가고 있습니다. 일반적으로 ViewModel에서 UI에 대한 참조를 갖는 것은 좋지 않습니다. “왜?” 그러나 이것은 Stackoverflow :)에 게시해야 할 또 다른 질문입니다.
-
Focus 관련 문제를 추적하는 가장 좋은 방법은 .Net 소스 코드를 디버깅하는 것입니다. 농담이 없습니다. 많은 시간을 절약했습니다. .net 소스 코드 디버깅을 활성화하려면 Shawn Bruke의 블로그를 참조하십시오 .
-
마지막으로 ViewModel에서 포커스를 설정하는 데 사용하는 일반적인 방법은 첨부 속성입니다. UIElement에 설정할 수있는 매우 간단한 첨부 속성을 작성했습니다. 예를 들어 ViewModel의 “IsFocused”속성에 바인딩 할 수 있습니다. 여기있어:
public static class FocusExtension { public static bool GetIsFocused(DependencyObject obj) { return (bool) obj.GetValue(IsFocusedProperty); } public static void SetIsFocused(DependencyObject obj, bool value) { obj.SetValue(IsFocusedProperty, value); } public static readonly DependencyProperty IsFocusedProperty = DependencyProperty.RegisterAttached( "IsFocused", typeof (bool), typeof (FocusExtension), new UIPropertyMetadata(false, OnIsFocusedPropertyChanged)); private static void OnIsFocusedPropertyChanged( DependencyObject d, DependencyPropertyChangedEventArgs e) { var uie = (UIElement) d; if ((bool) e.NewValue) { uie.Focus(); // Don't care about false values. } } }
이제 뷰 (XAML)에서이 속성을 ViewModel에 바인딩 할 수 있습니다.
<TextBox local:FocusExtension.IsFocused="{Binding IsUserNameFocused}" />
도움이 되었기를 바랍니다 :). 답변 # 2를 참조하지 않는 경우.
건배.
답변
나는이 질문이 지금까지 천 번 이상 대답되었다는 것을 알고 있지만, 비슷한 문제가있는 다른 사람들을 도울 것으로 생각되는 Anvaka의 기여를 약간 수정했습니다.
먼저 위의 첨부 속성을 다음과 같이 변경했습니다.
public static class FocusExtension
{
public static readonly DependencyProperty IsFocusedProperty =
DependencyProperty.RegisterAttached("IsFocused", typeof(bool?), typeof(FocusExtension), new FrameworkPropertyMetadata(IsFocusedChanged){BindsTwoWayByDefault = true});
public static bool? GetIsFocused(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return (bool?)element.GetValue(IsFocusedProperty);
}
public static void SetIsFocused(DependencyObject element, bool? value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(IsFocusedProperty, value);
}
private static void IsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var fe = (FrameworkElement)d;
if (e.OldValue == null)
{
fe.GotFocus += FrameworkElement_GotFocus;
fe.LostFocus += FrameworkElement_LostFocus;
}
if (!fe.IsVisible)
{
fe.IsVisibleChanged += new DependencyPropertyChangedEventHandler(fe_IsVisibleChanged);
}
if ((bool)e.NewValue)
{
fe.Focus();
}
}
private static void fe_IsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
{
var fe = (FrameworkElement)sender;
if (fe.IsVisible && (bool)((FrameworkElement)sender).GetValue(IsFocusedProperty))
{
fe.IsVisibleChanged -= fe_IsVisibleChanged;
fe.Focus();
}
}
private static void FrameworkElement_GotFocus(object sender, RoutedEventArgs e)
{
((FrameworkElement)sender).SetValue(IsFocusedProperty, true);
}
private static void FrameworkElement_LostFocus(object sender, RoutedEventArgs e)
{
((FrameworkElement)sender).SetValue(IsFocusedProperty, false);
}
}
가시성 참조를 추가 한 이유는 탭이었습니다. 처음에 보이는 탭 이외의 다른 탭에서 연결된 속성을 사용한 경우 컨트롤에 수동으로 초점을 맞출 때까지 연결된 속성이 작동하지 않은 것 같습니다.
다른 장애물은 기본 속성이 포커스를 잃었을 때 거짓으로 재설정하는보다 우아한 방법을 만드는 것이 었습니다. 이곳에서 잃어버린 초점 이벤트가 시작되었습니다.
<TextBox
Text="{Binding Description}"
FocusExtension.IsFocused="{Binding IsFocused}"/>
가시성 문제를 처리하는 더 좋은 방법이 있으면 알려주세요.
참고 : BindsTwoWayByDefault를 DependencyProperty에 넣을 것을 제안한 Apfelkuacha에게 감사드립니다. 나는 오래 전에 내 자신의 코드로 수행했지만이 게시물을 업데이트하지 않았습니다. 이 변경으로 인해 WPF 코드에서 더 이상 Mode = TwoWay가 필요하지 않습니다.
답변
가장 좋은 방법은 MVVM 원칙을 깨끗하게 유지하는 것이므로 기본적으로 MVVM Light와 함께 제공된 메신저 클래스를 사용해야하며 사용 방법은 다음과 같습니다.
viewmodel (exampleViewModel.cs)에서 다음을 작성하십시오.
Messenger.Default.Send<string>("focus", "DoFocus");
이제 View.cs (XAML이 아닌 view.xaml.cs)에서 생성자에 다음을 작성하십시오.
public MyView()
{
InitializeComponent();
Messenger.Default.Register<string>(this, "DoFocus", doFocus);
}
public void doFocus(string msg)
{
if (msg == "focus")
this.txtcode.Focus();
}
이 방법은 코드가 적고 MVVM 표준을 유지하면서도 훌륭합니다.
답변
이것들 중 어느 것도 나를 위해 정확하게 일한 것은 아니지만 다른 사람들의 이익을 위해 이미 여기에 제공된 코드 중 일부를 기반으로 작성했습니다.
사용법은 다음과 같습니다.
<TextBox ... h:FocusBehavior.IsFocused="True"/>
구현은 다음과 같습니다.
/// <summary>
/// Behavior allowing to put focus on element from the view model in a MVVM implementation.
/// </summary>
public static class FocusBehavior
{
#region Dependency Properties
/// <summary>
/// <c>IsFocused</c> dependency property.
/// </summary>
public static readonly DependencyProperty IsFocusedProperty =
DependencyProperty.RegisterAttached("IsFocused", typeof(bool?),
typeof(FocusBehavior), new FrameworkPropertyMetadata(IsFocusedChanged));
/// <summary>
/// Gets the <c>IsFocused</c> property value.
/// </summary>
/// <param name="element">The element.</param>
/// <returns>Value of the <c>IsFocused</c> property or <c>null</c> if not set.</returns>
public static bool? GetIsFocused(DependencyObject element)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
return (bool?)element.GetValue(IsFocusedProperty);
}
/// <summary>
/// Sets the <c>IsFocused</c> property value.
/// </summary>
/// <param name="element">The element.</param>
/// <param name="value">The value.</param>
public static void SetIsFocused(DependencyObject element, bool? value)
{
if (element == null)
{
throw new ArgumentNullException("element");
}
element.SetValue(IsFocusedProperty, value);
}
#endregion Dependency Properties
#region Event Handlers
/// <summary>
/// Determines whether the value of the dependency property <c>IsFocused</c> has change.
/// </summary>
/// <param name="d">The dependency object.</param>
/// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param>
private static void IsFocusedChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
// Ensure it is a FrameworkElement instance.
var fe = d as FrameworkElement;
if (fe != null && e.OldValue == null && e.NewValue != null && (bool)e.NewValue)
{
// Attach to the Loaded event to set the focus there. If we do it here it will
// be overridden by the view rendering the framework element.
fe.Loaded += FrameworkElementLoaded;
}
}
/// <summary>
/// Sets the focus when the framework element is loaded and ready to receive input.
/// </summary>
/// <param name="sender">The sender.</param>
/// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
private static void FrameworkElementLoaded(object sender, RoutedEventArgs e)
{
// Ensure it is a FrameworkElement instance.
var fe = sender as FrameworkElement;
if (fe != null)
{
// Remove the event handler registration.
fe.Loaded -= FrameworkElementLoaded;
// Set the focus to the given framework element.
fe.Focus();
// Determine if it is a text box like element.
var tb = fe as TextBoxBase;
if (tb != null)
{
// Select all text to be ready for replacement.
tb.SelectAll();
}
}
}
#endregion Event Handlers
}
답변
이것은 오래된 스레드이지만 Anavanka의 승인 된 답변 문제를 해결하는 코드에 대한 답변이없는 것 같습니다. 뷰 모델의 속성을 false로 설정하거나 속성을로 설정하면 작동하지 않습니다 true, 사용자가 수동으로 다른 것을 클릭 한 다음 다시 true로 설정합니다. 이 경우에도 Zamotic의 솔루션을 안정적으로 작동시킬 수 없었습니다.
위의 토론 중 일부를 종합하면 아래 코드가 나와 다음과 같은 문제를 해결합니다.
public static class FocusExtension
{
public static bool GetIsFocused(DependencyObject obj)
{
return (bool)obj.GetValue(IsFocusedProperty);
}
public static void SetIsFocused(DependencyObject obj, bool value)
{
obj.SetValue(IsFocusedProperty, value);
}
public static readonly DependencyProperty IsFocusedProperty =
DependencyProperty.RegisterAttached(
"IsFocused", typeof(bool), typeof(FocusExtension),
new UIPropertyMetadata(false, null, OnCoerceValue));
private static object OnCoerceValue(DependencyObject d, object baseValue)
{
if ((bool)baseValue)
((UIElement)d).Focus();
else if (((UIElement) d).IsFocused)
Keyboard.ClearFocus();
return ((bool)baseValue);
}
}
그럼에도 불구하고 이것은 여전히 코드 숨김에서 한 줄로 수행 할 수있는 무언가에 대해 복잡하며 CoerceValue는 실제로 이런 식으로 사용되도록 의도되지 않았으므로 코드 숨김이 갈 길입니다.
답변
필자의 경우 OnIsFocusedPropertyChanged 메서드를 변경할 때까지 FocusExtension이 작동하지 않았습니다. 원래는 중단 점이 프로세스를 중지했을 때 디버그에서만 작동했습니다. 런타임에 프로세스가 너무 빠르며 아무 일도 일어나지 않았습니다. 이 작은 수정과 친구 작업의 도움으로 두 시나리오에서 모두 잘 작동합니다.
private static void OnIsFocusedPropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
var uie = (UIElement)d;
if ((bool)e.NewValue)
{
var action = new Action(() => uie.Dispatcher.BeginInvoke((Action)(() => uie.Focus())));
Task.Factory.StartNew(action);
}
}
답변
문제는 IsUserNameFocused가 true로 설정되면 false가되지 않는다는 것입니다. 이를 통해 FrameworkElement의 GotFocus 및 LostFocus를 처리하여 문제를 해결합니다.
소스 코드 형식에 문제가 있었으므로 여기에 링크가 있습니다.
