2017-01-27 2 views
0

저는 C# -WPF에서 일하고 있습니다.UserControl에서 속성을 다시 평가하십시오.

나는 간단한 UserControl을 만들었습니다. 좌표를 사용하면 이미지에 X를 그릴 수 있습니다.

매개 변수는 다음과 같습니다

  • 센터 포인트 : 크로스
  • 전경 센터 : 십자가

내 Cross.xaml에 대한 두께 : 십자가

  • 두께의 색상

    <UserControl x:Name="userControl" 
          x:Class="Project.Cross"> 
        <Grid> 
         <Line Stroke="{Binding Foreground, ElementName=userControl}" 
           StrokeThickness="{Binding Thickness, ElementName=userControl}" 
           X1="{Binding X1, ElementName=userControl, Mode=OneWay}" 
           X2="{Binding X2, ElementName=userControl, Mode=OneWay}" 
           Y1="{Binding Y1, ElementName=userControl, Mode=OneWay}" 
           Y2="{Binding Y2, ElementName=userControl, Mode=OneWay}" /> 
    
         <Line Stroke="{Binding Foreground, ElementName=userControl}" 
           StrokeThickness="{Binding Thickness, ElementName=userControl}" 
           X1="{Binding X2, ElementName=userControl, Mode=OneWay}" 
           X2="{Binding X1, ElementName=userControl, Mode=OneWay}" 
           Y1="{Binding Y1, ElementName=userControl, Mode=OneWay}" 
           Y2="{Binding Y2, ElementName=userControl, Mode=OneWay}"/> 
        </Grid> 
    </UserControl> 
    

    내 Cross.xaml.cs는 :

    public partial class Cross : UserControl 
    { 
        public Cross() 
        { 
         InitializeComponent(); 
        } 
    
        public readonly static DependencyProperty CenterPointProperty = DependencyProperty.Register("CenterPoint", 
         typeof(PointF), typeof(Cross), 
         new PropertyMetadata(default(PointF))); 
    
        public PointF CenterPoint 
        { 
         get { return (PointF)GetValue(CenterPointProperty); } 
         set { SetValue(CenterPointProperty, value); } 
        } 
    
        public readonly static DependencyProperty ThicknessProperty = DependencyProperty.Register("Thickness", 
         typeof(int), typeof(Cross), 
         new PropertyMetadata(2)); 
    
        public int Thickness 
        { 
         get { return (int)GetValue(ThicknessProperty); } 
         set { SetValue(ThicknessProperty, value); } 
        } 
    
        public float X1 
        { 
         get 
         { 
          return (float)(CenterPoint.X - (Width/2)); 
         } 
        } 
        public float X2 
        { 
         get 
         { 
          return (float)(CenterPoint.X + (Width/2)); 
         } 
        } 
        public float Y1 
        { 
         get 
         { 
          return (float)(CenterPoint.Y - (Height/2)); 
         } 
        } 
        public float Y2 
        { 
         get 
         { 
          return (float)(CenterPoint.Y + (Height/2)); 
         } 
        } 
    } 
    

    나는 그것을 좋아 호출 할 수 있습니다 :

    <local:Cross CenterPoint="{Binding Point}" Thickness="8" Foreground="Yellow" Height="40" Width="40"/> 
    

    I은 ​​문제가 있다면, 십자가가 표시되지 않습니다. 중단 점을 추가했습니다. CenterPoint를 변경하면 값 X1, X2 ...이 새로 고쳐지지 않는 것 같습니다. C#에서 이러한 값을 다시 계산하도록하려면 어떻게해야합니까? 당신이 X1에 바인딩을 원하는 경우

    당신에게

  • +0

    local : Cross가 정의 된 xaml을 표시 할 수 있습니까? 예를 들어 그 안에 무엇이 들어 있는가? –

    +0

    질문을 이해할 수 없습니다. Cross.xaml 파일에 내 로컬 네임 스페이스에서 UserControl'Cross'를 정의했습니다. –

    +0

    난 그냥 왜 사용자 정의 컨트롤의 너비와 높이를 기반으로 고정 된 크기로 십자가를 그려야하고 그 대상을 대상 개체에 상대적으로 위치를 설정하여 그리는 무엇이든 주위에 그 개체를 이동하지 않습니다 궁금하네요. 그래서 나는 당신이 십자가를 그리는 것을 궁금해하고있었습니다. –

    답변

    1

    MM8의 방법 등 X1를 업데이트 작동을하지만,에 해결해야 할 추가적인 문제가 있습니다 제어가 작동하도록하십시오.

    좌표 속성을 업데이트하는 다른 방법을 사용하고 있습니다. read-only dependency propertiesX1 등을 입력하고 CenterPoint이 변경되고 컨트롤의 크기가 변경되면 사용자 정의 컨트롤을 업데이트하십시오.

    은 또한에 윈폼에게 PointF을 변경 한 XY에 대한 double를 사용하고, WPF는 선 두께에 대한 float를 사용하고 당신은뿐만 아니라 전체 걸릴 수 있기 때문에 내가뿐만 아니라 Thickness float에 변경했습니다 WPF의 System.Windows.Point, 이점.

    는 I 실제 크기가 0 X 0이고 WidthHeightNaN을 때 그렇지, 좌표 속성 만 제어 작성에 설정한다 중요하다 SizeChanged 이벤트의 좌표를 갱신하고있다.

    마지막으로, 당신은 디자인 타임 속성 값입니다 HeightWidth 달리 "라이브"업데이트 ActualWidthActualHeight를 사용한다. 고정 값인 WidthHeight을 지정하면 효과가 동일합니다. ActualWidthActualHeight을 사용하면 원하는 경우 용기에 맞게 늘릴 수 있습니다.Line.X1 등 바인딩 소스를 업데이트 할 수 없기 때문에

    public partial class Cross : UserControl 
    { 
        public Cross() 
        { 
         InitializeComponent(); 
    
         SizeChanged += Cross_SizeChanged; 
        } 
    
        private void Cross_SizeChanged(object sender, SizeChangedEventArgs e) 
        { 
         UpdateXYProperties(); 
        } 
    
        protected void UpdateXYProperties() 
        { 
         X1 = (float)(CenterPoint.X - (ActualWidth/2)); 
         X2 = (float)(CenterPoint.X + (ActualWidth/2)); 
         Y1 = (float)(CenterPoint.Y - (ActualHeight/2)); 
         Y2 = (float)(CenterPoint.Y + (ActualHeight/2)); 
        } 
    
        public readonly static DependencyProperty CenterPointProperty = DependencyProperty.Register(nameof(CenterPoint), 
         typeof(Point), typeof(Cross), 
         new PropertyMetadata(default(Point), CenterPoint_PropertyChanged)); 
    
        private static void CenterPoint_PropertyChanged(DependencyObject obj, DependencyPropertyChangedEventArgs e) 
        { 
         ((Cross)obj).UpdateXYProperties(); 
        } 
    
        public Point CenterPoint 
        { 
         get { return (Point)GetValue(CenterPointProperty); } 
         set { SetValue(CenterPointProperty, value); } 
        } 
    
        public readonly static DependencyProperty ThicknessProperty = DependencyProperty.Register(nameof(Thickness), 
         typeof(float), typeof(Cross), 
         new PropertyMetadata(2.0F)); 
    
        public float Thickness 
        { 
         get { return (float)GetValue(ThicknessProperty); } 
         set { SetValue(ThicknessProperty, value); } 
        } 
    
        #region Read-Only Properties 
        #region X1 Property 
        public float X1 
        { 
         get { return (float)GetValue(X1Property); } 
         protected set { SetValue(X1PropertyKey, value); } 
        } 
    
        internal static readonly DependencyPropertyKey X1PropertyKey = 
         DependencyProperty.RegisterReadOnly("X1", typeof(float), typeof(Cross), 
          new PropertyMetadata(0.0F)); 
    
        public static readonly DependencyProperty X1Property = X1PropertyKey.DependencyProperty; 
        #endregion X1 Property 
    
        #region X2 Property 
        public float X2 
        { 
         get { return (float)GetValue(X2Property); } 
         protected set { SetValue(X2PropertyKey, value); } 
        } 
    
        internal static readonly DependencyPropertyKey X2PropertyKey = 
         DependencyProperty.RegisterReadOnly("X2", typeof(float), typeof(Cross), 
          new PropertyMetadata(0.0F)); 
    
        public static readonly DependencyProperty X2Property = X2PropertyKey.DependencyProperty; 
        #endregion X2 Property 
    
        #region Y1 Property 
        public float Y1 
        { 
         get { return (float)GetValue(Y1Property); } 
         protected set { SetValue(Y1PropertyKey, value); } 
        } 
    
        internal static readonly DependencyPropertyKey Y1PropertyKey = 
         DependencyProperty.RegisterReadOnly("Y1", typeof(float), typeof(Cross), 
          new PropertyMetadata(0.0F)); 
    
        public static readonly DependencyProperty Y1Property = Y1PropertyKey.DependencyProperty; 
        #endregion Y1 Property 
    
        #region Y2 Property 
        public float Y2 
        { 
         get { return (float)GetValue(Y2Property); } 
         protected set { SetValue(Y2PropertyKey, value); } 
        } 
    
        internal static readonly DependencyPropertyKey Y2PropertyKey = 
         DependencyProperty.RegisterReadOnly("Y2", typeof(float), typeof(Cross), 
          new PropertyMetadata(0.0F)); 
    
        public static readonly DependencyProperty Y2Property = Y2PropertyKey.DependencyProperty; 
        #endregion Y2 Property 
        #endregion Read-Only Properties 
    } 
    

    마지막으로, 당신은 (즉,이 경우 자신의 X1 등의), 명시 적으로 바인딩 Mode=OneWay 할 필요가 없습니다, 그래서 그들은 이미있어 OneWay 기본적으로

    <Grid> 
        <Line 
         Stroke="{Binding Foreground, ElementName=userControl}" 
         StrokeThickness="{Binding Thickness, ElementName=userControl}" 
         X1="{Binding X1, ElementName=userControl}" 
         X2="{Binding X2, ElementName=userControl}" 
         Y1="{Binding Y1, ElementName=userControl}" 
         Y2="{Binding Y2, ElementName=userControl}" 
         /> 
    
        <Line 
         Stroke="{Binding Foreground, ElementName=userControl}" 
         StrokeThickness="{Binding Thickness, ElementName=userControl}" 
         X1="{Binding X2, ElementName=userControl}" 
         X2="{Binding X1, ElementName=userControl}" 
         Y1="{Binding Y1, ElementName=userControl}" 
         Y2="{Binding Y2, ElementName=userControl}" 
         /> 
    </Grid> 
    

    마지막으로, 거의 확실히 적어도 다음 CenterPoint 디자인의 효과는 컨트롤의 실제 중심이 아닌 경우 컨트롤의 경계의 교차 외부를 상쇄하는 것입니다. 그것이 당신의 의도라면,이 단락의 나머지 부분을 읽는 것을 귀찮게하지 마십시오. 그 의도되지 않은 경우 다음과 같이 UpdateXYProperties()를 다시 작성하고 CenterPoint 재산 잃을 수 :

    protected void UpdateXYProperties() 
    { 
        X1 = 0; 
        X2 = (float)ActualWidth; 
        Y1 = 0; 
        Y2 = (float)ActualHeight; 
    } 
    

    을하지만 당신과 세인트 앤드류에게 달려 있습니다.

    +0

    이 솔루션을 시도했지만 응용 프로그램을 실행할 수 있습니다. "교차에 대한 생성자가 예외 발생"과 같은 XmlParseException이 있습니다. –

    +0

    @ A.Pissicat 예외를 생성 한 실제 코드를 볼 수 있습니까? 내 것은 그렇게하지 않습니다. –

    +0

    오류를 발견했습니다. 'PropertyMetadata (0.0)'에 float가있는 것으로 간주되지 않았습니다. 나는이 명령을'PropertyMetadata (default (float))'로 바꾸었고 오류가 없다. 여전히 십자가는 볼 수 없지만 프로젝트를 실행할 수 있습니다. 나는 그들이 왜 표시되지 않는지 찾고있다. –

    2

    감사 (이것은 내 문제를 해결하기 바란다), X2는, Y1 및 Y2는 읽기 전용 속성을 새로 얻을 수있는 센터 포인트 종속성 속성이 새 값으로 설정되어있을 때 UserControl은 INotifyPropertyChanged 인터페이스를 구현해야합니다. 그런 다음 종속성 속성에 대한 PropertyChangedCallback을 등록하고 읽기 전용 속성에 대한 PropertyChanged 이벤트 올릴 수 :

    public partial class Cross : UserControl, INotifyPropertyChanged 
    { 
        public Cross() 
        { 
         InitializeComponent(); 
        } 
    
        public readonly static DependencyProperty CenterPointProperty = DependencyProperty.Register("CenterPoint", 
         typeof(PointF), typeof(Cross), 
         new PropertyMetadata(default(PointF), new PropertyChangedCallback(OnCenterPointUpdated)))); 
    
        private static void OnCenterPointUpdated(DependencyObject d, DependencyPropertyChangedEventArgs e) 
        { 
         Cross cross = d as Cross; 
         cross.NotifyPropertyChanged("X1"); 
         cross.NotifyPropertyChanged("X2"); 
         cross.NotifyPropertyChanged("Y1"); 
         cross.NotifyPropertyChanged("Y2"); 
        } 
    
        public event PropertyChangedEventHandler PropertyChanged; 
        private void NotifyPropertyChanged(string propertyName) 
        { 
         if (PropertyChanged != null) 
          PropertyChanged(this, new PropertyChangedEventArgs(propertyName)); 
        } 
    
        ... 
    }